@crvouga/mockingbird-service-stripe 1.5.0 → 1.6.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/CHANGELOG.md +21 -0
- package/README.md +5 -0
- package/dist/{chunk-L4SSW3ZW.js → chunk-JLJVLLWF.js} +2 -2
- package/dist/{chunk-HLEW2SR7.js → chunk-JMK5BHFP.js} +19 -8
- package/dist/chunk-JMK5BHFP.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.js +1 -1
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-HLEW2SR7.js.map +0 -7
- /package/dist/{chunk-L4SSW3ZW.js.map → chunk-JLJVLLWF.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-stripe
|
|
2
2
|
|
|
3
|
+
## 1.6.0 (2026-09-29)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- per-option data-testids on the portal's plan and reason choices ([237e5ef](https://github.com/crvouga/mockingbird/commit/237e5efc5425be3062e75cdfbcf942e8590bcd90))
|
|
8
|
+
|
|
9
|
+
### Fixes and improvements
|
|
10
|
+
|
|
11
|
+
- name a missing invoice item list cursor an invoice item ([7cfc811](https://github.com/crvouga/mockingbird/commit/7cfc81125e5e5ee23cfb03644bb7db4fa5473fa2))
|
|
12
|
+
- keep a customer address country as sent unless it is two letters ([6547c6c](https://github.com/crvouga/mockingbird/commit/6547c6c41e35dcfb469ebd53fbbb31dedbe34379))
|
|
13
|
+
- refuse a malformed preferred_locales before an empty invoice_settings on customer create ([65b18ed](https://github.com/crvouga/mockingbird/commit/65b18ed74f072b856a9c5334c3039c17f705bf45))
|
|
14
|
+
- resolve a payment method list's cursors before its customer_account ([8df4ce6](https://github.com/crvouga/mockingbird/commit/8df4ce63462b0192e32b8a14ce411c136ac55639))
|
|
15
|
+
- refuse both price amounts before looking up the product ([86700e2](https://github.com/crvouga/mockingbird/commit/86700e2e22576a4ebb79d5caa2790a2c86954da5))
|
|
16
|
+
- refuse an empty expand before looking up a Checkout Session ([4eb1010](https://github.com/crvouga/mockingbird/commit/4eb1010153a26f321dbc2870a537f8e0842bc945))
|
|
17
|
+
- refuse an empty cursor on a customer's balance transactions ([05fe354](https://github.com/crvouga/mockingbird/commit/05fe3549de39fb1a0208e79eba3c12d35641e5c7))
|
|
18
|
+
- name the dispute, not the cursor, in a missing-cursor error ([036ed1a](https://github.com/crvouga/mockingbird/commit/036ed1a249d015242e068c9c6796a320a9483f5c))
|
|
19
|
+
- name a missing portal configuration "configuration" ([d62e1df](https://github.com/crvouga/mockingbird/commit/d62e1df914536adef44a34414a0e42bfc726961a))
|
|
20
|
+
- leave portal configuration listing out of live parity walks ([ea11169](https://github.com/crvouga/mockingbird/commit/ea11169571ed61c2308ad5cb13fc07fa907ee9b2))
|
|
21
|
+
- refuse an empty search query before an empty expand ([2d0a11a](https://github.com/crvouga/mockingbird/commit/2d0a11aa1aab9e925597e63a1ec9df1744f8f9ef))
|
|
22
|
+
- show redacted startup output when stripe listen fails ([6c86bcc](https://github.com/crvouga/mockingbird/commit/6c86bccfe4654442cf20d2ab4e7114b63bd1ac04))
|
|
23
|
+
|
|
3
24
|
## 1.5.0 (2026-09-29)
|
|
4
25
|
|
|
5
26
|
### Features
|
package/README.md
CHANGED
|
@@ -283,6 +283,11 @@ billing.stripe.com) where the customer manages their billing, as the session's c
|
|
|
283
283
|
through a SetupIntent, which becomes the customer's and each subscription's default; **Make
|
|
284
284
|
default**; **Delete** a non-default card); billing information (the configured `allowed_updates`,
|
|
285
285
|
`customer.updated` with `previous_attributes`); invoice history with **Pay** for open invoices.
|
|
286
|
+
Repeated choices carry a per-option `data-testid` on the wrapping `<label class="option">`
|
|
287
|
+
(tapping it checks the radio), so a test-id-only driver can pick one: each plan is
|
|
288
|
+
`stripe-mock-portal-price-option-<price lookup_key, else price id>` and each cancellation reason
|
|
289
|
+
is `stripe-mock-portal-reason-<reason>` (e.g. `…-too_expensive`). The generic
|
|
290
|
+
`stripe-mock-portal-price-option` and `stripe-mock-portal-reason` ids stay on the radios.
|
|
286
291
|
- **Deep links** open on the flow's page — cancel (with a retention offer to accept), update, update
|
|
287
292
|
confirmation, payment method, billing details — and on completion honour `after_completion`:
|
|
288
293
|
`redirect` (302), `hosted_confirmation` (its `custom_message`) or the homepage. Every action
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createRuntime,
|
|
3
3
|
validateAccounts
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JMK5BHFP.js";
|
|
5
5
|
|
|
6
6
|
// src/server.ts
|
|
7
7
|
import { readFileSync } from "node:fs";
|
|
@@ -385,4 +385,4 @@ export {
|
|
|
385
385
|
createServer2 as createServer,
|
|
386
386
|
serveTarget
|
|
387
387
|
};
|
|
388
|
-
//# sourceMappingURL=chunk-
|
|
388
|
+
//# sourceMappingURL=chunk-JLJVLLWF.js.map
|
|
@@ -1559,7 +1559,7 @@ var restoreNamespace = (sqlite, namespace, snapshot) => {
|
|
|
1559
1559
|
};
|
|
1560
1560
|
|
|
1561
1561
|
// ../core/dist/version.js
|
|
1562
|
-
var PACKAGE_VERSION = true ? "1.
|
|
1562
|
+
var PACKAGE_VERSION = true ? "1.6.0" : UNRELEASED_VERSION;
|
|
1563
1563
|
|
|
1564
1564
|
// ../core/dist/signing.js
|
|
1565
1565
|
var encoder = new TextEncoder();
|
|
@@ -5978,11 +5978,15 @@ var paginate = async (collection, params, options) => {
|
|
|
5978
5978
|
const endingBefore = params.ending_before;
|
|
5979
5979
|
const all = await collection.list({ order: "newest" });
|
|
5980
5980
|
const exists = options.exists ?? (() => true);
|
|
5981
|
+
if (options.rejectEmptyCursors) {
|
|
5982
|
+
if (startingAfter === "") throw parameterInvalidEmpty("starting_after");
|
|
5983
|
+
if (endingBefore === "") throw parameterInvalidEmpty("ending_before");
|
|
5984
|
+
}
|
|
5981
5985
|
const cursorIndex = (id, param) => {
|
|
5982
5986
|
const index = all.findIndex(
|
|
5983
5987
|
(entry) => entry.id === id && exists(entry.value)
|
|
5984
5988
|
);
|
|
5985
|
-
if (index === -1) throw resourceMissing(options.kind, id, param, 400);
|
|
5989
|
+
if (index === -1) throw resourceMissing(options.kind, id, options.cursorParam ?? param, 400);
|
|
5986
5990
|
return index;
|
|
5987
5991
|
};
|
|
5988
5992
|
if (typeof startingAfter === "string" && startingAfter !== "")
|
|
@@ -9576,7 +9580,8 @@ var checkoutSessionHandlers = (services) => ({
|
|
|
9576
9580
|
},
|
|
9577
9581
|
GetCheckoutSessionsSession: async (context) => {
|
|
9578
9582
|
const scope = requestScope(services, context);
|
|
9579
|
-
queryParams(context);
|
|
9583
|
+
const params = queryParams(context);
|
|
9584
|
+
if (params.expand === "") throw parameterInvalidEmpty("expand");
|
|
9580
9585
|
const id = context.params.session ?? "";
|
|
9581
9586
|
const session = scope.account.checkoutSessions.get(id);
|
|
9582
9587
|
if (!session)
|
|
@@ -9839,7 +9844,7 @@ var cancelPage = (context, subscriptionId, messages) => {
|
|
|
9839
9844
|
const immediately = cancel.mode === "immediately";
|
|
9840
9845
|
const when = immediately ? "Your subscription will be canceled immediately." : `Your subscription will be canceled, but is still available until the end of your billing period on ${formatDate(subscription.current_period_end)}.`;
|
|
9841
9846
|
const reasons = cancel.cancellation_reason.enabled ? `<h2>Tell us why you're canceling</h2>${cancel.cancellation_reason.options.filter((option) => CANCELLATION_REASONS.includes(option)).map(
|
|
9842
|
-
(option) => `<label class="option"><input type="radio" name="reason" value="${option}" data-testid="stripe-mock-portal-reason"${messages.values?.reason === option ? " checked" : ""}><span>${escapeHtml2(REASON_LABELS[option] ?? option)}</span></label>`
|
|
9847
|
+
(option) => `<label class="option" data-testid="stripe-mock-portal-reason-${escapeHtml2(option)}"><input type="radio" name="reason" value="${option}" data-testid="stripe-mock-portal-reason"${messages.values?.reason === option ? " checked" : ""}><span>${escapeHtml2(REASON_LABELS[option] ?? option)}</span></label>`
|
|
9843
9848
|
).join(
|
|
9844
9849
|
""
|
|
9845
9850
|
)}<label class="field"><span>Anything else? (optional)</span><textarea name="comment" data-testid="stripe-mock-portal-comment">${escapeHtml2(messages.values?.comment ?? "")}</textarea></label>` : "";
|
|
@@ -9870,7 +9875,7 @@ var updatePage = (context, subscriptionId, messages) => {
|
|
|
9870
9875
|
const options = allowed.includes("price") ? portalProducts(scope.account, config).flatMap((product) => product.prices).map((priceId) => {
|
|
9871
9876
|
const price = scope.account.prices.get(priceId);
|
|
9872
9877
|
if (!price?.active) return "";
|
|
9873
|
-
return `<label class="option"><input type="radio" name="price" value="${price.id}" data-testid="stripe-mock-portal-price-option"${price.id === selected ? " checked" : ""}><span><strong>${escapeHtml2(productName(context, price))}</strong>${price.id === item?.price ? '<span class="chip">Current plan</span>' : ""}<div class="meta">${escapeHtml2(priceLabel(price))}</div></span></label>`;
|
|
9878
|
+
return `<label class="option" data-testid="stripe-mock-portal-price-option-${escapeHtml2(price.lookup_key ?? price.id)}"><input type="radio" name="price" value="${price.id}" data-testid="stripe-mock-portal-price-option"${price.id === selected ? " checked" : ""}><span><strong>${escapeHtml2(productName(context, price))}</strong>${price.id === item?.price ? '<span class="chip">Current plan</span>' : ""}<div class="meta">${escapeHtml2(priceLabel(price))}</div></span></label>`;
|
|
9874
9879
|
}).join("") : `<input type="hidden" name="price" value="${item?.price ?? ""}">`;
|
|
9875
9880
|
const quantity = allowed.includes("quantity") ? `<label class="field"><span>Quantity</span><input type="number" min="1" name="quantity" value="${escapeHtml2(messages.values?.quantity ?? String(item?.quantity ?? 1))}" data-testid="stripe-mock-portal-quantity"></label>` : "";
|
|
9876
9881
|
return `<h1>Update your plan</h1>
|
|
@@ -11324,12 +11329,13 @@ var expanders4 = (scope) => {
|
|
|
11324
11329
|
"data.invoice_settings.default_payment_method": defaultPaymentMethod
|
|
11325
11330
|
};
|
|
11326
11331
|
};
|
|
11332
|
+
var CUSTOMER_PARAM_ORDER = ["preferred_locales"];
|
|
11327
11333
|
var customerHandlers = (services) => {
|
|
11328
11334
|
const render3 = (scope, customer, params) => applyExpand(renderCustomer(customer), params.expand, expanders4(scope));
|
|
11329
11335
|
return {
|
|
11330
11336
|
PostCustomers: async (context) => {
|
|
11331
11337
|
const scope = requestScope(services, context);
|
|
11332
|
-
const params = bodyParams(context);
|
|
11338
|
+
const params = bodyParams(context, { order: CUSTOMER_PARAM_ORDER });
|
|
11333
11339
|
const id = scope.ids.next("cus_");
|
|
11334
11340
|
const base2 = {
|
|
11335
11341
|
id,
|
|
@@ -11446,6 +11452,7 @@ var customerHandlers = (services) => {
|
|
|
11446
11452
|
url: `/v1/customers/${id}/balance_transactions`,
|
|
11447
11453
|
// Stripe names an unknown cursor on this list by its internal model.
|
|
11448
11454
|
kind: "abstracttransaction",
|
|
11455
|
+
rejectEmptyCursors: true,
|
|
11449
11456
|
where: (record) => record.customer === id && matchesCreated(record.created, params.created),
|
|
11450
11457
|
render: renderCustomerBalanceTransaction
|
|
11451
11458
|
});
|
|
@@ -11494,6 +11501,7 @@ var disputeHandlers = (services) => ({
|
|
|
11494
11501
|
const page = await paginate(scope.account.disputes, params, {
|
|
11495
11502
|
url: "/v1/disputes",
|
|
11496
11503
|
kind: "dispute",
|
|
11504
|
+
cursorParam: "dispute",
|
|
11497
11505
|
where: (record) => matchesCreated(record.created, params.created) && (charge === null || record.charge === charge) && (paymentIntent === null || record.payment_intent === paymentIntent),
|
|
11498
11506
|
render: renderDispute
|
|
11499
11507
|
});
|
|
@@ -12040,6 +12048,9 @@ var paymentMethodHandlers = (services) => ({
|
|
|
12040
12048
|
where: (record) => (customer === null || record.customer === customer) && (type === null || record.type === type),
|
|
12041
12049
|
render: renderPaymentMethod
|
|
12042
12050
|
});
|
|
12051
|
+
const account = stringOf(params, "customer_account");
|
|
12052
|
+
if (account !== null && account !== "")
|
|
12053
|
+
throw resourceMissing("customer", account, "customer_account", 400);
|
|
12043
12054
|
return jsonRes(200, page);
|
|
12044
12055
|
},
|
|
12045
12056
|
PostPaymentMethods: async (context) => {
|
|
@@ -17375,7 +17386,7 @@ var StripeAPI = class {
|
|
|
17375
17386
|
"customer"
|
|
17376
17387
|
).init
|
|
17377
17388
|
);
|
|
17378
|
-
if (customerAccount !== void 0 && customerAccount !== "")
|
|
17389
|
+
if (customerAccount !== void 0 && customerAccount !== "" && context.operation.operationId !== "GetPaymentMethods")
|
|
17379
17390
|
return this.errorResponse(
|
|
17380
17391
|
resourceMissing("customer", customerAccount, "customer_account", 400).init
|
|
17381
17392
|
);
|
|
@@ -17623,4 +17634,4 @@ export {
|
|
|
17623
17634
|
createRuntime2 as createRuntime,
|
|
17624
17635
|
StripeAPI
|
|
17625
17636
|
};
|
|
17626
|
-
//# sourceMappingURL=chunk-
|
|
17637
|
+
//# sourceMappingURL=chunk-JMK5BHFP.js.map
|