@volter/twin-stripe 2.0.22 → 2.0.23
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type SemanticsContext } from '@volter/world-core';
|
|
2
2
|
import { type Row } from './shared.js';
|
|
3
3
|
/** A customer's now: its test clock's frozen time when it is on one (docs.stripe.com/billing/testing/test-clocks), the
|
|
4
4
|
* World's otherwise. */
|
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
// A subscription's invoices over time: the first one Checkout pays, and each renewal. Time's moves are made
|
|
2
|
+
// as the twin's trial end already made them: caught up to the customer's clock (the World's, or its test
|
|
3
|
+
// clock) whenever the twin is asked anything (../stripe-server.ts), each checked against the machines in
|
|
4
|
+
// ../manifest.ts.
|
|
5
|
+
//
|
|
6
|
+
// - Checkout's subscription session pays the first invoice with the card the customer entered, which becomes the
|
|
7
|
+
// subscription's default payment method (docs.stripe.com/payments/checkout/how-checkout-works); nothing is due
|
|
8
|
+
// on a trial's.
|
|
9
|
+
// - At each period's end Stripe drafts a `subscription_cycle` invoice for the next period and advances the
|
|
10
|
+
// period; a trial's end is the first such renewal, and the subscription is active from then
|
|
11
|
+
// (docs.stripe.com/billing/subscriptions/overview#how-payments-work-subscriptions,
|
|
12
|
+
// docs.stripe.com/billing/subscriptions/trials).
|
|
13
|
+
// - About an hour after, Stripe finalizes the draft and charges the subscription's default payment method,
|
|
14
|
+
// else the customer's (docs.stripe.com/invoicing/integration/workflow-transitions#finalized,
|
|
15
|
+
// docs.stripe.com/api/subscriptions/object#subscription_object-default_payment_method).
|
|
16
|
+
// - A declined renewal leaves the invoice open with its attempt counted and the subscription past_due
|
|
17
|
+
// (docs.stripe.com/billing/subscriptions/overview#payment-status); paying the invoice later, through the API
|
|
18
|
+
// (docs.stripe.com/api/invoices/pay) or on the customer portal (docs.stripe.com/customer-management), makes it
|
|
19
|
+
// active again.
|
|
20
|
+
//
|
|
21
|
+
// Where the documentation stops and the twin decides: Stripe retries a failed renewal on its Smart Retries
|
|
22
|
+
// schedule and may then cancel or mark the subscription unpaid; the twin makes no retry (next_payment_attempt
|
|
23
|
+
// is null) and leaves it past_due until the invoice is paid. A paused subscription (pause_collection) is not renewed.
|
|
24
|
+
// - One set to cancel at its period's end is canceled when the period ends, with no renewal
|
|
25
|
+
// (docs.stripe.com/billing/subscriptions/cancel#cancel-at-end-of-cycle).
|
|
26
|
+
import { runAsVendorMove } from '@volter/world-core';
|
|
1
27
|
import { addBillingInterval, applyCouponDiscount, declineFor, mintClientSecret, priceAmount, resolveSubscriptionBillingInterval } from "../stripe-twin.js";
|
|
2
28
|
import { finalizedFields } from "./invoices.js";
|
|
3
29
|
import { mintCharge } from "./payment-intents.js";
|
|
@@ -195,6 +221,10 @@ export async function payOpenInvoice(ctx, invoiceId, paymentMethod) {
|
|
|
195
221
|
* moment it was due: a period that ended renews (a trial's end among them) or, set to cancel, cancels; a renewal
|
|
196
222
|
* drafted an hour or more ago is finalized and charged. */
|
|
197
223
|
export async function advanceBilling(ctx, only) {
|
|
224
|
+
// the billing clock is the vendor's own move, wherever a handler reaches it: never the request's caller's
|
|
225
|
+
return runAsVendorMove(() => advanceBillingDue(ctx, only));
|
|
226
|
+
}
|
|
227
|
+
async function advanceBillingDue(ctx, only) {
|
|
198
228
|
const at = at_(ctx);
|
|
199
229
|
for (let guard = 0; guard < 10_000 && (await billingStep(ctx, at, only)); guard++)
|
|
200
230
|
;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/twin-stripe",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.23",
|
|
4
4
|
"description": "Local Stripe twin — a faithful, stateful local Stripe API your real `stripe` SDK talks to unmodified. Mirror, simulate, and fork. Built on @volter/world-core.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"twin",
|
|
@@ -56,15 +56,15 @@
|
|
|
56
56
|
"postpack": "node ../../../scripts/publish/prepare-publish.mjs postpack"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@volter/world-ui": "0.1.
|
|
59
|
+
"@volter/world-ui": "0.1.22",
|
|
60
60
|
"react": "^19.2.7",
|
|
61
61
|
"react-dom": "^19.2.7"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@volter/world-core": "2.0.
|
|
64
|
+
"@volter/world-core": "2.0.22"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@volter/world-core": "2.0.
|
|
67
|
+
"@volter/world-core": "2.0.22",
|
|
68
68
|
"@volter/world-tooling": "0.1.0",
|
|
69
69
|
"@types/bun": "^1.2.20",
|
|
70
70
|
"@types/node": "^24.0.0",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
// is null) and leaves it past_due until the invoice is paid. A paused subscription (pause_collection) is not renewed.
|
|
24
24
|
// - One set to cancel at its period's end is canceled when the period ends, with no renewal
|
|
25
25
|
// (docs.stripe.com/billing/subscriptions/cancel#cancel-at-end-of-cycle).
|
|
26
|
-
import type
|
|
26
|
+
import { runAsVendorMove, type SemanticsContext } from '@volter/world-core';
|
|
27
27
|
import { addBillingInterval, applyCouponDiscount, declineFor, mintClientSecret, priceAmount, resolveSubscriptionBillingInterval } from '../stripe-twin.ts';
|
|
28
28
|
import { finalizedFields } from './invoices.ts';
|
|
29
29
|
import { mintCharge } from './payment-intents.ts';
|
|
@@ -227,6 +227,11 @@ export async function payOpenInvoice(ctx: SemanticsContext, invoiceId: string, p
|
|
|
227
227
|
* moment it was due: a period that ended renews (a trial's end among them) or, set to cancel, cancels; a renewal
|
|
228
228
|
* drafted an hour or more ago is finalized and charged. */
|
|
229
229
|
export async function advanceBilling(ctx: SemanticsContext, only?: (sub: Row) => boolean): Promise<void> {
|
|
230
|
+
// the billing clock is the vendor's own move, wherever a handler reaches it: never the request's caller's
|
|
231
|
+
return runAsVendorMove(() => advanceBillingDue(ctx, only));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function advanceBillingDue(ctx: SemanticsContext, only?: (sub: Row) => boolean): Promise<void> {
|
|
230
235
|
const at = at_(ctx);
|
|
231
236
|
for (let guard = 0; guard < 10_000 && (await billingStep(ctx, at, only)); guard++);
|
|
232
237
|
}
|