@efaj/pulumi-dynamic-stripe 0.0.2 → 0.1.0-252fa04
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/CHANGELOG.md +8 -0
- package/Makefile +12 -3
- package/README.md +38 -4
- package/biome.json +37 -0
- package/dist/StripePaymentLink.d.ts +15 -1
- package/dist/StripePaymentLink.js +41 -18
- package/dist/StripePrice.d.ts +44 -3
- package/dist/StripePrice.js +52 -6
- package/dist/StripeProduct.d.ts +2 -2
- package/dist/StripeProduct.js +10 -8
- package/dist/enums.d.ts +24 -0
- package/dist/enums.js +32 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +28 -0
- package/docs/troubleshooting-stuck-state.md +63 -0
- package/package.json +41 -37
- package/tests/index.test.ts +884 -315
- package/tests/integration.test.ts +46 -0
- package/vitest.config.ts +7 -0
- package/jest.config.js +0 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0](https://github.com/efaj/pulumi-dynamic-stripe/compare/v0.0.2...v0.1.0) (2026-08-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* Handle delete case w/o apiKey gracefully ([0639e18](https://github.com/efaj/pulumi-dynamic-stripe/commit/0639e18beff72d6d4fe251be171e2e2e4bc47bda))
|
package/Makefile
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
.PHONY: all install build test clean
|
|
1
|
+
.PHONY: all install build lint test clean
|
|
2
2
|
|
|
3
|
-
all: install build test
|
|
3
|
+
all: install build lint test
|
|
4
4
|
|
|
5
5
|
install:
|
|
6
6
|
npm install
|
|
@@ -8,8 +8,17 @@ install:
|
|
|
8
8
|
build:
|
|
9
9
|
npm run build
|
|
10
10
|
|
|
11
|
+
lint:
|
|
12
|
+
npm run lint
|
|
13
|
+
|
|
14
|
+
lint-fix:
|
|
15
|
+
npm run lint:fix
|
|
16
|
+
|
|
11
17
|
test:
|
|
12
|
-
npm test
|
|
18
|
+
npm run test
|
|
19
|
+
|
|
20
|
+
test-integration:
|
|
21
|
+
npm run test:integration
|
|
13
22
|
|
|
14
23
|
clean:
|
|
15
24
|
rm -rf dist node_modules package-lock.json
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# pulumi-dynamic-stripe
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-

|
|
3
|
+

|
|
4
|
+

|
|
5
5
|
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fefaj%2Fpulumi-dynamic-stripe?ref=badge_shield)
|
|
6
6
|
|
|
7
7
|
A native Pulumi Dynamic Provider for Stripe.
|
|
@@ -28,7 +28,7 @@ Contributions to add more dynamic providers for other Stripe resources are highl
|
|
|
28
28
|
## Installation
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
npm install pulumi-dynamic-stripe
|
|
31
|
+
npm install @efaj/pulumi-dynamic-stripe
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Usage
|
|
@@ -37,7 +37,7 @@ Here is a full example of provisioning a Product, attaching a Price to it, and g
|
|
|
37
37
|
|
|
38
38
|
```typescript
|
|
39
39
|
import * as pulumi from "@pulumi/pulumi";
|
|
40
|
-
import { Product, Price, PaymentLink } from "pulumi-dynamic-stripe";
|
|
40
|
+
import { Product, Price, PaymentLink } from "@efaj/pulumi-dynamic-stripe";
|
|
41
41
|
|
|
42
42
|
const config = new pulumi.Config();
|
|
43
43
|
const stripeApiKey = config.requireSecret("stripeApiKey");
|
|
@@ -71,3 +71,37 @@ export const paymentUrl = premiumPaymentLink.url;
|
|
|
71
71
|
## How it works
|
|
72
72
|
|
|
73
73
|
Behind the scenes, this library defines custom Pulumi Dynamic Resource Providers that implement the CRUD operations for Stripe entities via the `@pulumi/pulumi` and `stripe` Node packages.
|
|
74
|
+
|
|
75
|
+
## Resource Deletion & State Fallbacks
|
|
76
|
+
|
|
77
|
+
Stripe entities generally cannot be hard-deleted via the API; instead, this provider safely **deactivates** them (e.g., setting `active: false` on Payment Links, Products, and Prices) when Pulumi destroys the resource.
|
|
78
|
+
|
|
79
|
+
Due to the way Pulumi manages dynamic provider state, if an input property like `apiKey` is not explicitly declared as a public output on the resource class, it may be scrubbed from the state file. When Pulumi attempts to delete a replaced or destroyed resource, it reads from the old state. If the `apiKey` is missing from the state during deletion, the provider will gracefully attempt to fall back to the `STRIPE_SECRET_KEY` or `STRIPE_API_KEY` environment variables.
|
|
80
|
+
|
|
81
|
+
If no API key is found in the state or environment variables, the provider will log a warning and **skip the Stripe deactivation (NoOp)** to allow Pulumi to successfully finish deleting the resource from its internal state without crashing.
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
If you wish to contribute or build the project locally, please use the provided `Makefile`.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Install dependencies
|
|
89
|
+
make install
|
|
90
|
+
|
|
91
|
+
# Build the TypeScript source
|
|
92
|
+
make build
|
|
93
|
+
|
|
94
|
+
# Lint the codebase
|
|
95
|
+
make lint
|
|
96
|
+
|
|
97
|
+
# Run the Vitest test suite
|
|
98
|
+
make test
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Contributing & Releases
|
|
102
|
+
|
|
103
|
+
This project uses [Release Please](https://github.com/googleapis/release-please) to automate versioning, changelog generation, and NPM publishing.
|
|
104
|
+
|
|
105
|
+
When contributing, you **must** format your commit messages using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) (e.g., `feat: add new resource`, `fix: handle edge case`).
|
|
106
|
+
|
|
107
|
+
When your PR is merged into `main`, Release Please will automatically open a "Release PR" bumping the semantic version and updating the `CHANGELOG.md`. Merging that Release PR will trigger the GitHub Action to cut a GitHub Release and publish the new version to NPM.
|
package/biome.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.5.11/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"clientKind": "git",
|
|
6
|
+
"useIgnoreFile": true
|
|
7
|
+
},
|
|
8
|
+
"files": {
|
|
9
|
+
"includes": ["**", "!!**/dist"]
|
|
10
|
+
},
|
|
11
|
+
"formatter": {
|
|
12
|
+
"enabled": true,
|
|
13
|
+
"indentStyle": "tab"
|
|
14
|
+
},
|
|
15
|
+
"linter": {
|
|
16
|
+
"enabled": true,
|
|
17
|
+
"rules": {
|
|
18
|
+
"preset": "recommended",
|
|
19
|
+
"suspicious": {
|
|
20
|
+
"noExplicitAny": "off"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"javascript": {
|
|
25
|
+
"formatter": {
|
|
26
|
+
"quoteStyle": "double"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"assist": {
|
|
30
|
+
"enabled": true,
|
|
31
|
+
"actions": {
|
|
32
|
+
"source": {
|
|
33
|
+
"organizeImports": "on"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -6,6 +6,13 @@ export interface StripePaymentLinkArgs {
|
|
|
6
6
|
redirectUrl: pulumi.Input<string>;
|
|
7
7
|
allowPromotionCodes?: pulumi.Input<boolean>;
|
|
8
8
|
managedPayments?: pulumi.Input<boolean>;
|
|
9
|
+
automaticTax?: pulumi.Input<boolean>;
|
|
10
|
+
quantity?: pulumi.Input<number>;
|
|
11
|
+
adjustableQuantity?: pulumi.Input<{
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
minimum?: number;
|
|
14
|
+
maximum?: number;
|
|
15
|
+
}>;
|
|
9
16
|
}
|
|
10
17
|
export interface StripePaymentLinkProviderArgs {
|
|
11
18
|
apiKey: string;
|
|
@@ -14,10 +21,17 @@ export interface StripePaymentLinkProviderArgs {
|
|
|
14
21
|
redirectUrl: string;
|
|
15
22
|
allowPromotionCodes?: boolean;
|
|
16
23
|
managedPayments?: boolean;
|
|
24
|
+
automaticTax?: boolean;
|
|
25
|
+
quantity?: number;
|
|
26
|
+
adjustableQuantity?: {
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
minimum?: number;
|
|
29
|
+
maximum?: number;
|
|
30
|
+
};
|
|
17
31
|
}
|
|
18
32
|
export declare class StripePaymentLinkProvider implements pulumi.dynamic.ResourceProvider {
|
|
19
33
|
create(inputs: StripePaymentLinkProviderArgs): Promise<pulumi.dynamic.CreateResult>;
|
|
20
|
-
diff(
|
|
34
|
+
diff(_id: string, olds: StripePaymentLinkProviderArgs, news: StripePaymentLinkProviderArgs): Promise<pulumi.dynamic.DiffResult>;
|
|
21
35
|
delete(id: string, props: StripePaymentLinkProviderArgs): Promise<void>;
|
|
22
36
|
}
|
|
23
37
|
export declare class PaymentLink extends pulumi.dynamic.Resource {
|
|
@@ -39,30 +39,42 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.PaymentLink = exports.StripePaymentLinkProvider = void 0;
|
|
40
40
|
const pulumi = __importStar(require("@pulumi/pulumi"));
|
|
41
41
|
const stripe_1 = __importDefault(require("stripe"));
|
|
42
|
+
const utils_1 = require("./utils");
|
|
42
43
|
class StripePaymentLinkProvider {
|
|
43
44
|
async create(inputs) {
|
|
44
|
-
const stripe = new stripe_1.default(inputs.apiKey
|
|
45
|
+
const stripe = new stripe_1.default(inputs.apiKey);
|
|
45
46
|
const paymentLink = await stripe.paymentLinks.create({
|
|
46
|
-
line_items: [
|
|
47
|
+
line_items: [
|
|
48
|
+
{
|
|
47
49
|
price: inputs.priceId,
|
|
48
|
-
quantity: 1,
|
|
49
|
-
|
|
50
|
-
enabled
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
quantity: inputs.quantity ?? 1,
|
|
51
|
+
...(inputs.adjustableQuantity !== undefined
|
|
52
|
+
? inputs.adjustableQuantity.enabled
|
|
53
|
+
? { adjustable_quantity: inputs.adjustableQuantity }
|
|
54
|
+
: {}
|
|
55
|
+
: {
|
|
56
|
+
adjustable_quantity: {
|
|
57
|
+
enabled: true,
|
|
58
|
+
minimum: 1,
|
|
59
|
+
maximum: 100,
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
],
|
|
55
64
|
after_completion: {
|
|
56
|
-
type:
|
|
65
|
+
type: "redirect",
|
|
57
66
|
redirect: {
|
|
58
67
|
url: inputs.redirectUrl,
|
|
59
|
-
}
|
|
68
|
+
},
|
|
60
69
|
},
|
|
61
70
|
allow_promotion_codes: inputs.allowPromotionCodes,
|
|
62
|
-
...(inputs.managedPayments
|
|
71
|
+
...(inputs.managedPayments
|
|
72
|
+
? { managed_payments: { enabled: true } }
|
|
73
|
+
: {}),
|
|
74
|
+
...(inputs.automaticTax ? { automatic_tax: { enabled: true } } : {}),
|
|
63
75
|
metadata: {
|
|
64
|
-
sparks: inputs.sparksAmount
|
|
65
|
-
}
|
|
76
|
+
sparks: inputs.sparksAmount,
|
|
77
|
+
},
|
|
66
78
|
});
|
|
67
79
|
return {
|
|
68
80
|
id: paymentLink.id,
|
|
@@ -70,10 +82,10 @@ class StripePaymentLinkProvider {
|
|
|
70
82
|
...inputs,
|
|
71
83
|
paymentLinkId: paymentLink.id,
|
|
72
84
|
url: paymentLink.url,
|
|
73
|
-
}
|
|
85
|
+
},
|
|
74
86
|
};
|
|
75
87
|
}
|
|
76
|
-
async diff(
|
|
88
|
+
async diff(_id, olds, news) {
|
|
77
89
|
const replaces = [];
|
|
78
90
|
if (olds.priceId !== news.priceId)
|
|
79
91
|
replaces.push("priceId");
|
|
@@ -85,16 +97,24 @@ class StripePaymentLinkProvider {
|
|
|
85
97
|
replaces.push("allowPromotionCodes");
|
|
86
98
|
if (olds.managedPayments !== news.managedPayments)
|
|
87
99
|
replaces.push("managedPayments");
|
|
100
|
+
if (olds.automaticTax !== news.automaticTax)
|
|
101
|
+
replaces.push("automaticTax");
|
|
88
102
|
if (olds.apiKey !== news.apiKey)
|
|
89
103
|
replaces.push("apiKey");
|
|
104
|
+
if (olds.quantity !== news.quantity)
|
|
105
|
+
replaces.push("quantity");
|
|
106
|
+
if (JSON.stringify(olds.adjustableQuantity) !==
|
|
107
|
+
JSON.stringify(news.adjustableQuantity))
|
|
108
|
+
replaces.push("adjustableQuantity");
|
|
90
109
|
return {
|
|
91
110
|
changes: replaces.length > 0,
|
|
92
111
|
replaces,
|
|
93
112
|
};
|
|
94
113
|
}
|
|
95
114
|
async delete(id, props) {
|
|
96
|
-
|
|
97
|
-
|
|
115
|
+
await (0, utils_1.safeDeactivateStripeResource)("StripePaymentLinkProvider", id, props.apiKey, async (stripe) => {
|
|
116
|
+
await stripe.paymentLinks.update(id, { active: false });
|
|
117
|
+
});
|
|
98
118
|
}
|
|
99
119
|
}
|
|
100
120
|
exports.StripePaymentLinkProvider = StripePaymentLinkProvider;
|
|
@@ -108,6 +128,9 @@ class PaymentLink extends pulumi.dynamic.Resource {
|
|
|
108
128
|
redirectUrl: args.redirectUrl,
|
|
109
129
|
allowPromotionCodes: args.allowPromotionCodes,
|
|
110
130
|
managedPayments: args.managedPayments,
|
|
131
|
+
automaticTax: args.automaticTax,
|
|
132
|
+
quantity: args.quantity,
|
|
133
|
+
adjustableQuantity: args.adjustableQuantity,
|
|
111
134
|
paymentLinkId: undefined,
|
|
112
135
|
url: undefined,
|
|
113
136
|
}, opts);
|
package/dist/StripePrice.d.ts
CHANGED
|
@@ -1,19 +1,60 @@
|
|
|
1
1
|
import * as pulumi from "@pulumi/pulumi";
|
|
2
|
+
import type { BillingScheme, RecurringInterval, TaxBehavior, TiersMode, UsageType } from "./enums";
|
|
3
|
+
export interface RecurringArgs {
|
|
4
|
+
interval: pulumi.Input<RecurringInterval>;
|
|
5
|
+
intervalCount?: pulumi.Input<number>;
|
|
6
|
+
usageType?: pulumi.Input<UsageType>;
|
|
7
|
+
}
|
|
8
|
+
export interface TierArgs {
|
|
9
|
+
upTo: pulumi.Input<number | "inf">;
|
|
10
|
+
unitAmount?: pulumi.Input<number>;
|
|
11
|
+
flatAmount?: pulumi.Input<number>;
|
|
12
|
+
}
|
|
13
|
+
export interface TransformQuantityArgs {
|
|
14
|
+
divideBy: pulumi.Input<number>;
|
|
15
|
+
round: pulumi.Input<"up" | "down">;
|
|
16
|
+
}
|
|
2
17
|
export interface StripePriceArgs {
|
|
3
18
|
apiKey: pulumi.Input<string>;
|
|
4
19
|
productId: pulumi.Input<string>;
|
|
5
|
-
unitAmount: pulumi.Input<number>;
|
|
6
20
|
currency: pulumi.Input<string>;
|
|
21
|
+
unitAmount?: pulumi.Input<number>;
|
|
22
|
+
taxBehavior?: pulumi.Input<TaxBehavior>;
|
|
23
|
+
recurring?: pulumi.Input<RecurringArgs>;
|
|
24
|
+
billingScheme?: pulumi.Input<BillingScheme>;
|
|
25
|
+
tiersMode?: pulumi.Input<TiersMode>;
|
|
26
|
+
tiers?: pulumi.Input<pulumi.Input<TierArgs>[]>;
|
|
27
|
+
transformQuantity?: pulumi.Input<TransformQuantityArgs>;
|
|
28
|
+
}
|
|
29
|
+
export interface RecurringProviderArgs {
|
|
30
|
+
interval: RecurringInterval;
|
|
31
|
+
intervalCount?: number;
|
|
32
|
+
usageType?: UsageType;
|
|
33
|
+
}
|
|
34
|
+
export interface TierProviderArgs {
|
|
35
|
+
upTo: number | "inf";
|
|
36
|
+
unitAmount?: number;
|
|
37
|
+
flatAmount?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface TransformQuantityProviderArgs {
|
|
40
|
+
divideBy: number;
|
|
41
|
+
round: "up" | "down";
|
|
7
42
|
}
|
|
8
43
|
export interface StripePriceProviderArgs {
|
|
9
44
|
apiKey: string;
|
|
10
45
|
productId: string;
|
|
11
|
-
unitAmount: number;
|
|
12
46
|
currency: string;
|
|
47
|
+
unitAmount?: number;
|
|
48
|
+
taxBehavior?: TaxBehavior;
|
|
49
|
+
recurring?: RecurringProviderArgs;
|
|
50
|
+
billingScheme?: BillingScheme;
|
|
51
|
+
tiersMode?: TiersMode;
|
|
52
|
+
tiers?: TierProviderArgs[];
|
|
53
|
+
transformQuantity?: TransformQuantityProviderArgs;
|
|
13
54
|
}
|
|
14
55
|
export declare class StripePriceProvider implements pulumi.dynamic.ResourceProvider {
|
|
15
56
|
create(inputs: StripePriceProviderArgs): Promise<pulumi.dynamic.CreateResult>;
|
|
16
|
-
diff(
|
|
57
|
+
diff(_id: string, olds: StripePriceProviderArgs, news: StripePriceProviderArgs): Promise<pulumi.dynamic.DiffResult>;
|
|
17
58
|
delete(id: string, props: StripePriceProviderArgs): Promise<void>;
|
|
18
59
|
}
|
|
19
60
|
export declare class Price extends pulumi.dynamic.Resource {
|
package/dist/StripePrice.js
CHANGED
|
@@ -39,23 +39,55 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.Price = exports.StripePriceProvider = void 0;
|
|
40
40
|
const pulumi = __importStar(require("@pulumi/pulumi"));
|
|
41
41
|
const stripe_1 = __importDefault(require("stripe"));
|
|
42
|
+
const utils_1 = require("./utils");
|
|
42
43
|
class StripePriceProvider {
|
|
43
44
|
async create(inputs) {
|
|
44
|
-
const stripe = new stripe_1.default(inputs.apiKey
|
|
45
|
+
const stripe = new stripe_1.default(inputs.apiKey);
|
|
45
46
|
const price = await stripe.prices.create({
|
|
46
47
|
product: inputs.productId,
|
|
47
|
-
unit_amount: inputs.unitAmount,
|
|
48
48
|
currency: inputs.currency,
|
|
49
|
+
...(inputs.unitAmount !== undefined
|
|
50
|
+
? { unit_amount: inputs.unitAmount }
|
|
51
|
+
: {}),
|
|
52
|
+
tax_behavior: inputs.taxBehavior,
|
|
53
|
+
...(inputs.recurring
|
|
54
|
+
? {
|
|
55
|
+
recurring: {
|
|
56
|
+
interval: inputs.recurring.interval,
|
|
57
|
+
interval_count: inputs.recurring.intervalCount,
|
|
58
|
+
usage_type: inputs.recurring.usageType,
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
: {}),
|
|
62
|
+
billing_scheme: inputs.billingScheme,
|
|
63
|
+
tiers_mode: inputs.tiersMode,
|
|
64
|
+
...(inputs.tiers
|
|
65
|
+
? {
|
|
66
|
+
tiers: inputs.tiers.map((t) => ({
|
|
67
|
+
up_to: t.upTo,
|
|
68
|
+
unit_amount: t.unitAmount,
|
|
69
|
+
flat_amount: t.flatAmount,
|
|
70
|
+
})),
|
|
71
|
+
}
|
|
72
|
+
: {}),
|
|
73
|
+
...(inputs.transformQuantity
|
|
74
|
+
? {
|
|
75
|
+
transform_quantity: {
|
|
76
|
+
divide_by: inputs.transformQuantity.divideBy,
|
|
77
|
+
round: inputs.transformQuantity.round,
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
: {}),
|
|
49
81
|
});
|
|
50
82
|
return {
|
|
51
83
|
id: price.id,
|
|
52
84
|
outs: {
|
|
53
85
|
...inputs,
|
|
54
86
|
priceId: price.id,
|
|
55
|
-
}
|
|
87
|
+
},
|
|
56
88
|
};
|
|
57
89
|
}
|
|
58
|
-
async diff(
|
|
90
|
+
async diff(_id, olds, news) {
|
|
59
91
|
const replaces = [];
|
|
60
92
|
if (olds.productId !== news.productId)
|
|
61
93
|
replaces.push("productId");
|
|
@@ -63,6 +95,19 @@ class StripePriceProvider {
|
|
|
63
95
|
replaces.push("unitAmount");
|
|
64
96
|
if (olds.currency !== news.currency)
|
|
65
97
|
replaces.push("currency");
|
|
98
|
+
if (olds.taxBehavior !== news.taxBehavior)
|
|
99
|
+
replaces.push("taxBehavior");
|
|
100
|
+
if (JSON.stringify(olds.recurring) !== JSON.stringify(news.recurring))
|
|
101
|
+
replaces.push("recurring");
|
|
102
|
+
if (olds.billingScheme !== news.billingScheme)
|
|
103
|
+
replaces.push("billingScheme");
|
|
104
|
+
if (olds.tiersMode !== news.tiersMode)
|
|
105
|
+
replaces.push("tiersMode");
|
|
106
|
+
if (JSON.stringify(olds.tiers) !== JSON.stringify(news.tiers))
|
|
107
|
+
replaces.push("tiers");
|
|
108
|
+
if (JSON.stringify(olds.transformQuantity) !==
|
|
109
|
+
JSON.stringify(news.transformQuantity))
|
|
110
|
+
replaces.push("transformQuantity");
|
|
66
111
|
if (olds.apiKey !== news.apiKey)
|
|
67
112
|
replaces.push("apiKey");
|
|
68
113
|
return {
|
|
@@ -71,8 +116,9 @@ class StripePriceProvider {
|
|
|
71
116
|
};
|
|
72
117
|
}
|
|
73
118
|
async delete(id, props) {
|
|
74
|
-
|
|
75
|
-
|
|
119
|
+
await (0, utils_1.safeDeactivateStripeResource)("StripePriceProvider", id, props.apiKey, async (stripe) => {
|
|
120
|
+
await stripe.prices.update(id, { active: false });
|
|
121
|
+
});
|
|
76
122
|
}
|
|
77
123
|
}
|
|
78
124
|
exports.StripePriceProvider = StripePriceProvider;
|
package/dist/StripeProduct.d.ts
CHANGED
|
@@ -13,8 +13,8 @@ export interface StripeProductProviderArgs {
|
|
|
13
13
|
}
|
|
14
14
|
export declare class StripeProductProvider implements pulumi.dynamic.ResourceProvider {
|
|
15
15
|
create(inputs: StripeProductProviderArgs): Promise<pulumi.dynamic.CreateResult>;
|
|
16
|
-
diff(
|
|
17
|
-
update(id: string,
|
|
16
|
+
diff(_id: string, olds: StripeProductProviderArgs, news: StripeProductProviderArgs): Promise<pulumi.dynamic.DiffResult>;
|
|
17
|
+
update(id: string, _olds: StripeProductProviderArgs, news: StripeProductProviderArgs): Promise<pulumi.dynamic.UpdateResult>;
|
|
18
18
|
delete(id: string, props: StripeProductProviderArgs): Promise<void>;
|
|
19
19
|
}
|
|
20
20
|
export declare class Product extends pulumi.dynamic.Resource {
|
package/dist/StripeProduct.js
CHANGED
|
@@ -39,9 +39,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.Product = exports.StripeProductProvider = void 0;
|
|
40
40
|
const pulumi = __importStar(require("@pulumi/pulumi"));
|
|
41
41
|
const stripe_1 = __importDefault(require("stripe"));
|
|
42
|
+
const utils_1 = require("./utils");
|
|
42
43
|
class StripeProductProvider {
|
|
43
44
|
async create(inputs) {
|
|
44
|
-
const stripe = new stripe_1.default(inputs.apiKey
|
|
45
|
+
const stripe = new stripe_1.default(inputs.apiKey);
|
|
45
46
|
const product = await stripe.products.create({
|
|
46
47
|
name: inputs.name,
|
|
47
48
|
description: inputs.description,
|
|
@@ -52,10 +53,10 @@ class StripeProductProvider {
|
|
|
52
53
|
outs: {
|
|
53
54
|
...inputs,
|
|
54
55
|
productId: product.id,
|
|
55
|
-
}
|
|
56
|
+
},
|
|
56
57
|
};
|
|
57
58
|
}
|
|
58
|
-
async diff(
|
|
59
|
+
async diff(_id, olds, news) {
|
|
59
60
|
const changes = [];
|
|
60
61
|
if (olds.name !== news.name)
|
|
61
62
|
changes.push("name");
|
|
@@ -70,8 +71,8 @@ class StripeProductProvider {
|
|
|
70
71
|
replaces: [], // None require replacement, all can be updated
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
|
-
async update(id,
|
|
74
|
-
const stripe = new stripe_1.default(news.apiKey
|
|
74
|
+
async update(id, _olds, news) {
|
|
75
|
+
const stripe = new stripe_1.default(news.apiKey);
|
|
75
76
|
await stripe.products.update(id, {
|
|
76
77
|
name: news.name,
|
|
77
78
|
description: news.description,
|
|
@@ -81,12 +82,13 @@ class StripeProductProvider {
|
|
|
81
82
|
outs: {
|
|
82
83
|
...news,
|
|
83
84
|
productId: id,
|
|
84
|
-
}
|
|
85
|
+
},
|
|
85
86
|
};
|
|
86
87
|
}
|
|
87
88
|
async delete(id, props) {
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
await (0, utils_1.safeDeactivateStripeResource)("StripeProductProvider", id, props.apiKey, async (stripe) => {
|
|
90
|
+
await stripe.products.update(id, { active: false });
|
|
91
|
+
});
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
exports.StripeProductProvider = StripeProductProvider;
|
package/dist/enums.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const INF: "inf";
|
|
2
|
+
export declare enum TaxBehavior {
|
|
3
|
+
Inclusive = "inclusive",
|
|
4
|
+
Exclusive = "exclusive",
|
|
5
|
+
Unspecified = "unspecified"
|
|
6
|
+
}
|
|
7
|
+
export declare enum BillingScheme {
|
|
8
|
+
PerUnit = "per_unit",
|
|
9
|
+
Tiered = "tiered"
|
|
10
|
+
}
|
|
11
|
+
export declare enum TiersMode {
|
|
12
|
+
Graduated = "graduated",
|
|
13
|
+
Volume = "volume"
|
|
14
|
+
}
|
|
15
|
+
export declare enum RecurringInterval {
|
|
16
|
+
Day = "day",
|
|
17
|
+
Week = "week",
|
|
18
|
+
Month = "month",
|
|
19
|
+
Year = "year"
|
|
20
|
+
}
|
|
21
|
+
export declare enum UsageType {
|
|
22
|
+
Metered = "metered",
|
|
23
|
+
Licensed = "licensed"
|
|
24
|
+
}
|
package/dist/enums.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UsageType = exports.RecurringInterval = exports.TiersMode = exports.BillingScheme = exports.TaxBehavior = exports.INF = void 0;
|
|
4
|
+
exports.INF = "inf";
|
|
5
|
+
var TaxBehavior;
|
|
6
|
+
(function (TaxBehavior) {
|
|
7
|
+
TaxBehavior["Inclusive"] = "inclusive";
|
|
8
|
+
TaxBehavior["Exclusive"] = "exclusive";
|
|
9
|
+
TaxBehavior["Unspecified"] = "unspecified";
|
|
10
|
+
})(TaxBehavior || (exports.TaxBehavior = TaxBehavior = {}));
|
|
11
|
+
var BillingScheme;
|
|
12
|
+
(function (BillingScheme) {
|
|
13
|
+
BillingScheme["PerUnit"] = "per_unit";
|
|
14
|
+
BillingScheme["Tiered"] = "tiered";
|
|
15
|
+
})(BillingScheme || (exports.BillingScheme = BillingScheme = {}));
|
|
16
|
+
var TiersMode;
|
|
17
|
+
(function (TiersMode) {
|
|
18
|
+
TiersMode["Graduated"] = "graduated";
|
|
19
|
+
TiersMode["Volume"] = "volume";
|
|
20
|
+
})(TiersMode || (exports.TiersMode = TiersMode = {}));
|
|
21
|
+
var RecurringInterval;
|
|
22
|
+
(function (RecurringInterval) {
|
|
23
|
+
RecurringInterval["Day"] = "day";
|
|
24
|
+
RecurringInterval["Week"] = "week";
|
|
25
|
+
RecurringInterval["Month"] = "month";
|
|
26
|
+
RecurringInterval["Year"] = "year";
|
|
27
|
+
})(RecurringInterval || (exports.RecurringInterval = RecurringInterval = {}));
|
|
28
|
+
var UsageType;
|
|
29
|
+
(function (UsageType) {
|
|
30
|
+
UsageType["Metered"] = "metered";
|
|
31
|
+
UsageType["Licensed"] = "licensed";
|
|
32
|
+
})(UsageType || (exports.UsageType = UsageType = {}));
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./enums"), exports);
|
|
17
18
|
__exportStar(require("./StripePaymentLink"), exports);
|
|
18
|
-
__exportStar(require("./StripeProduct"), exports);
|
|
19
19
|
__exportStar(require("./StripePrice"), exports);
|
|
20
|
+
__exportStar(require("./StripeProduct"), exports);
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Stripe from "stripe";
|
|
2
|
+
/**
|
|
3
|
+
* Safely deactivates a Stripe resource during Pulumi deletion.
|
|
4
|
+
* Falls back to environment variables if the apiKey is missing from state.
|
|
5
|
+
* Prevents Pulumi state engine crashes when a resource cannot be deactivated.
|
|
6
|
+
*/
|
|
7
|
+
export declare function safeDeactivateStripeResource(providerName: string, resourceId: string, apiKeyFromState: string | undefined, deactivateFn: (stripe: Stripe) => Promise<void>): Promise<void>;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.safeDeactivateStripeResource = safeDeactivateStripeResource;
|
|
7
|
+
const stripe_1 = __importDefault(require("stripe"));
|
|
8
|
+
/**
|
|
9
|
+
* Safely deactivates a Stripe resource during Pulumi deletion.
|
|
10
|
+
* Falls back to environment variables if the apiKey is missing from state.
|
|
11
|
+
* Prevents Pulumi state engine crashes when a resource cannot be deactivated.
|
|
12
|
+
*/
|
|
13
|
+
async function safeDeactivateStripeResource(providerName, resourceId, apiKeyFromState, deactivateFn) {
|
|
14
|
+
const apiKey = apiKeyFromState ||
|
|
15
|
+
process.env.STRIPE_SECRET_KEY ||
|
|
16
|
+
process.env.STRIPE_API_KEY;
|
|
17
|
+
if (!apiKey) {
|
|
18
|
+
console.warn(`[${providerName}] Skipping deletion of ${resourceId} due to missing apiKey in state and environment variables.`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const stripe = new stripe_1.default(apiKey);
|
|
23
|
+
await deactivateFn(stripe);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.warn(`[${providerName}] Failed to deactivate ${resourceId}:`, error);
|
|
27
|
+
}
|
|
28
|
+
}
|