@volter/twin-stripe 3.0.0 → 3.0.1
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/README.md +51 -21
- package/dist/generated/pack-facts.json +3 -3
- package/dist/journeys/coverage.json +596 -0
- package/dist/journeys/customer-life.json +6108 -0
- package/dist/journeys/customer-life.outline.md +371 -0
- package/dist/journeys/decisions.json +677 -0
- package/dist/journeys/demand.json +706 -0
- package/dist/journeys/score.json +853 -0
- package/dist/journeys/unreachable.json +102 -0
- package/dist/journeys/vendor-examples.json +8010 -0
- package/dist/spec/SOURCE.md +5 -1
- package/dist/spec/doc-examples.json +445 -0
- package/dist/spec/sources.json +135 -207
- package/dist/src/cli.d.ts +0 -1
- package/dist/src/cli.js +0 -2
- package/dist/src/engine/after-payment.d.ts +0 -1
- package/dist/src/engine/after-payment.js +0 -1
- package/dist/src/engine/common.d.ts +5 -5
- package/dist/src/engine/common.js +13 -11
- package/dist/src/engine/connect.d.ts +0 -21
- package/dist/src/engine/connect.js +1 -82
- package/dist/src/engine/customers.d.ts +0 -8
- package/dist/src/engine/customers.js +0 -22
- package/dist/src/engine/display.d.ts +0 -3
- package/dist/src/engine/display.js +0 -3
- package/dist/src/engine/files.d.ts +0 -7
- package/dist/src/engine/files.js +0 -10
- package/dist/src/engine/invoices.d.ts +6 -9
- package/dist/src/engine/invoices.js +56 -29
- package/dist/src/engine/issuing.d.ts +6 -8
- package/dist/src/engine/issuing.js +19 -10
- package/dist/src/engine/ledger.d.ts +0 -1
- package/dist/src/engine/ledger.js +0 -1
- package/dist/src/engine/oauth.js +1 -2
- package/dist/src/engine/refunds.js +2 -27
- package/dist/src/engine/stripe.d.ts +2 -7
- package/dist/src/engine/stripe.js +34 -83
- package/dist/src/engine/subscriptions.d.ts +0 -1
- package/dist/src/engine/subscriptions.js +0 -1
- package/dist/src/engine/version.d.ts +0 -2
- package/dist/src/engine/version.js +17 -6
- package/dist/src/fetch.js +2 -2
- package/dist/src/generated/surface.gen.json +1 -1
- package/dist/src/generated/ui.gen.json +1 -1
- package/dist/src/index.js +5 -3
- package/dist/src/manifest.js +348 -220
- package/dist/src/screens/billing-portal.js +5 -5
- package/dist/src/screens/{connect-oauth.d.ts → checkout-js.d.ts} +0 -1
- package/dist/src/screens/checkout-js.js +84 -0
- package/dist/src/screens/connect-onboarding.js +3 -3
- package/dist/src/screens/dashboard.d.ts +1 -1
- package/dist/src/screens/dashboard.js +52 -53
- package/dist/src/screens/stripe-js.js +53 -93
- package/dist/src/semantics/account.d.ts +2 -0
- package/dist/src/semantics/account.js +8 -0
- package/dist/src/semantics/accounts.js +3 -1
- package/dist/src/semantics/around.js +3 -6
- package/dist/src/semantics/billing_portal.d.ts +0 -1
- package/dist/src/semantics/billing_portal.js +1 -7
- package/dist/src/semantics/checkout.d.ts +1 -1
- package/dist/src/semantics/checkout.js +18 -15
- package/dist/src/semantics/clock.js +1 -7
- package/dist/src/semantics/customers.d.ts +1 -2
- package/dist/src/semantics/customers.js +32 -38
- package/dist/src/semantics/entitlements.d.ts +0 -2
- package/dist/src/semantics/entitlements.js +4 -50
- package/dist/src/semantics/events.d.ts +2 -3
- package/dist/src/semantics/events.js +6 -11
- package/dist/src/semantics/index.js +16 -38
- package/dist/src/semantics/invoices.d.ts +3 -8
- package/dist/src/semantics/invoices.js +134 -127
- package/dist/src/semantics/issuing.d.ts +6 -0
- package/dist/src/semantics/issuing.js +77 -0
- package/dist/src/semantics/payment_intents.d.ts +0 -1
- package/dist/src/semantics/payment_intents.js +5 -13
- package/dist/src/semantics/payment_methods.d.ts +0 -2
- package/dist/src/semantics/payment_methods.js +2 -26
- package/dist/src/semantics/payouts.d.ts +1 -0
- package/dist/src/semantics/payouts.js +8 -1
- package/dist/src/semantics/products.d.ts +1 -3
- package/dist/src/semantics/products.js +3 -14
- package/dist/src/semantics/refunds.d.ts +1 -2
- package/dist/src/semantics/refunds.js +1 -5
- package/dist/src/semantics/shared.d.ts +64 -336
- package/dist/src/semantics/shared.js +326 -1336
- package/dist/src/semantics/states.d.ts +20 -89
- package/dist/src/semantics/states.js +116 -334
- package/dist/src/semantics/subscriptions.d.ts +1 -2
- package/dist/src/semantics/subscriptions.js +23 -145
- package/dist/src/semantics/test_helpers.d.ts +2 -5
- package/dist/src/semantics/test_helpers.js +121 -43
- package/dist/src/semantics/webhook_endpoints.d.ts +2 -0
- package/dist/src/semantics/webhook_endpoints.js +26 -0
- package/generated/pack-facts.json +3 -3
- package/journeys/coverage.json +596 -0
- package/journeys/customer-life.json +6108 -0
- package/journeys/customer-life.outline.md +371 -0
- package/journeys/decisions.json +677 -0
- package/journeys/demand.json +706 -0
- package/journeys/score.json +853 -0
- package/journeys/unreachable.json +102 -0
- package/journeys/vendor-examples.json +8010 -0
- package/package.json +4 -3
- package/spec/SOURCE.md +5 -1
- package/spec/doc-examples.json +445 -0
- package/spec/sources.json +135 -207
- package/src/cli.ts +0 -3
- package/src/engine/after-payment.ts +0 -2
- package/src/engine/balance.ts +0 -1
- package/src/engine/checkout.ts +0 -1
- package/src/engine/common.ts +19 -17
- package/src/engine/connect.ts +1 -79
- package/src/engine/customers.ts +0 -25
- package/src/engine/display.ts +2 -3
- package/src/engine/files.ts +0 -13
- package/src/engine/invoices.ts +64 -33
- package/src/engine/issuing.ts +16 -11
- package/src/engine/ledger.ts +0 -2
- package/src/engine/oauth.ts +1 -2
- package/src/engine/onboarding.ts +0 -1
- package/src/engine/params.ts +0 -1
- package/src/engine/payment-intents.ts +0 -1
- package/src/engine/payment-methods.ts +0 -1
- package/src/engine/refunds.ts +2 -28
- package/src/engine/renewals.ts +0 -1
- package/src/engine/stripe.ts +35 -83
- package/src/engine/subscriptions.ts +0 -3
- package/src/engine/transfers.ts +0 -1
- package/src/engine/version.ts +15 -7
- package/src/engine/webhooks.ts +0 -2
- package/src/fetch.ts +2 -2
- package/src/generated/surface.gen.json +1 -1
- package/src/generated/ui.gen.json +1 -1
- package/src/index.ts +6 -4
- package/src/manifest.ts +348 -220
- package/src/screens/billing-portal.tsx +5 -7
- package/src/screens/checkout-js.ts +80 -0
- package/src/screens/checkout.tsx +0 -2
- package/src/screens/connect-onboarding.tsx +3 -5
- package/src/screens/dashboard.tsx +53 -73
- package/src/screens/stripe-js.ts +57 -125
- package/src/semantics/account.ts +10 -0
- package/src/semantics/account_links.ts +0 -1
- package/src/semantics/accounts.ts +8 -7
- package/src/semantics/apps.ts +1 -2
- package/src/semantics/around.ts +3 -6
- package/src/semantics/balance.ts +0 -1
- package/src/semantics/balance_transactions.ts +1 -3
- package/src/semantics/billing_portal.ts +1 -7
- package/src/semantics/charges.ts +1 -6
- package/src/semantics/checkout.ts +16 -12
- package/src/semantics/clock.ts +1 -8
- package/src/semantics/coupons.ts +0 -1
- package/src/semantics/customers.ts +32 -35
- package/src/semantics/doors.ts +2 -3
- package/src/semantics/entitlements.ts +1 -45
- package/src/semantics/events.ts +7 -14
- package/src/semantics/index.ts +16 -38
- package/src/semantics/invoice_payments.ts +1 -3
- package/src/semantics/invoices.ts +124 -119
- package/src/semantics/issuing.ts +74 -0
- package/src/semantics/payment_intents.ts +10 -17
- package/src/semantics/payment_methods.ts +2 -25
- package/src/semantics/payouts.ts +9 -3
- package/src/semantics/prices.ts +0 -1
- package/src/semantics/products.ts +4 -14
- package/src/semantics/promotion_codes.ts +0 -1
- package/src/semantics/radar.ts +1 -3
- package/src/semantics/refunds.ts +2 -11
- package/src/semantics/shared.ts +350 -1382
- package/src/semantics/states.ts +109 -330
- package/src/semantics/subscriptions.ts +25 -145
- package/src/semantics/test_helpers.ts +109 -43
- package/src/semantics/transfers.ts +1 -3
- package/src/semantics/webhook_endpoints.ts +27 -0
- package/src/server.ts +0 -1
- package/dist/src/engine/billing.d.ts +0 -5
- package/dist/src/engine/billing.js +0 -6
- package/dist/src/engine/charges.d.ts +0 -6
- package/dist/src/engine/charges.js +0 -13
- package/dist/src/engine/connect-settings.d.ts +0 -16
- package/dist/src/engine/connect-settings.js +0 -26
- package/dist/src/engine/coupons.d.ts +0 -0
- package/dist/src/engine/coupons.js +0 -5
- package/dist/src/engine/credit-notes.d.ts +0 -1
- package/dist/src/engine/credit-notes.js +0 -5
- package/dist/src/engine/disputes.d.ts +0 -0
- package/dist/src/engine/disputes.js +0 -9
- package/dist/src/engine/entitlements.d.ts +0 -1
- package/dist/src/engine/entitlements.js +0 -4
- package/dist/src/engine/ephemeral-keys.d.ts +0 -0
- package/dist/src/engine/ephemeral-keys.js +0 -4
- package/dist/src/engine/front.d.ts +0 -5
- package/dist/src/engine/front.js +0 -25
- package/dist/src/engine/payment-links.d.ts +0 -1
- package/dist/src/engine/payment-links.js +0 -5
- package/dist/src/engine/plans.d.ts +0 -6
- package/dist/src/engine/plans.js +0 -26
- package/dist/src/engine/platform.d.ts +0 -39
- package/dist/src/engine/platform.js +0 -34
- package/dist/src/engine/products.d.ts +0 -0
- package/dist/src/engine/products.js +0 -4
- package/dist/src/engine/setup-intents.d.ts +0 -1
- package/dist/src/engine/setup-intents.js +0 -4
- package/dist/src/engine/subscription-schedules.d.ts +0 -3
- package/dist/src/engine/subscription-schedules.js +0 -1
- package/dist/src/engine/tax.d.ts +0 -7
- package/dist/src/engine/tax.js +0 -28
- package/dist/src/engine/terminal.d.ts +0 -4
- package/dist/src/engine/terminal.js +0 -20
- package/dist/src/engine/test-clocks.d.ts +0 -5
- package/dist/src/engine/test-clocks.js +0 -9
- package/dist/src/engine/tokens.d.ts +0 -7
- package/dist/src/engine/tokens.js +0 -20
- package/dist/src/engine/treasury.d.ts +0 -23
- package/dist/src/engine/treasury.js +0 -45
- package/dist/src/screens/connect-oauth.js +0 -333
- package/dist/src/semantics/disputes.d.ts +0 -2
- package/dist/src/semantics/disputes.js +0 -5
- package/dist/src/semantics/invoiceitems.d.ts +0 -3
- package/dist/src/semantics/invoiceitems.js +0 -59
- package/dist/src/semantics/setup_intents.d.ts +0 -3
- package/dist/src/semantics/setup_intents.js +0 -41
- package/dist/src/semantics/subscription_items.d.ts +0 -5
- package/dist/src/semantics/subscription_items.js +0 -55
- package/dist/src/semantics/subscription_schedules.d.ts +0 -4
- package/dist/src/semantics/subscription_schedules.js +0 -60
- package/src/engine/billing.ts +0 -16
- package/src/engine/charges.ts +0 -19
- package/src/engine/connect-settings.ts +0 -23
- package/src/engine/coupons.ts +0 -5
- package/src/engine/credit-notes.ts +0 -6
- package/src/engine/disputes.ts +0 -9
- package/src/engine/entitlements.ts +0 -5
- package/src/engine/ephemeral-keys.ts +0 -3
- package/src/engine/front.ts +0 -31
- package/src/engine/payment-links.ts +0 -6
- package/src/engine/plans.ts +0 -42
- package/src/engine/platform.ts +0 -47
- package/src/engine/products.ts +0 -3
- package/src/engine/setup-intents.ts +0 -5
- package/src/engine/subscription-schedules.ts +0 -10
- package/src/engine/tax.ts +0 -39
- package/src/engine/terminal.ts +0 -23
- package/src/engine/test-clocks.ts +0 -11
- package/src/engine/tokens.ts +0 -22
- package/src/engine/treasury.ts +0 -47
- package/src/screens/connect-oauth.tsx +0 -376
- package/src/semantics/disputes.ts +0 -12
- package/src/semantics/invoiceitems.ts +0 -59
- package/src/semantics/setup_intents.ts +0 -45
- package/src/semantics/subscription_items.ts +0 -54
- package/src/semantics/subscription_schedules.ts +0 -66
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
const unexpected = (verb, allowed) => ({
|
|
2
|
-
status: 400,
|
|
3
|
-
code: 'payment_intent_unexpected_state',
|
|
4
|
-
message: `This PaymentIntent could not be ${verb} because it has a status of {from}. ${allowed}`,
|
|
5
|
-
});
|
|
6
1
|
const OPEN = ['requires_payment_method', 'requires_confirmation', 'requires_action', 'requires_capture', 'processing'];
|
|
7
2
|
/** A move no API call makes: Stripe's own (`vendor`), the clock's (`time`), or the person on a
|
|
8
3
|
* Stripe-hosted page (`external`: Checkout, the billing portal, a hosted invoice or 3DS page). */
|
|
@@ -22,18 +17,9 @@ const paymentIntentStatus = {
|
|
|
22
17
|
transitions: [
|
|
23
18
|
// created with its payment method, it "enters the `requires_confirmation` status and is ready to confirm" (the same page)
|
|
24
19
|
{ operation: 'PostPaymentIntents', from: ['requires_payment_method'], to: 'requires_confirmation', source: 'https://docs.stripe.com/payments/paymentintents/lifecycle' },
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
from: ['requires_payment_method', 'requires_confirmation', 'requires_action'],
|
|
29
|
-
to,
|
|
30
|
-
refusal: { status: 400, code: 'payment_intent_unexpected_state', message: 'You cannot confirm this PaymentIntent because it has a status of {from}.' },
|
|
31
|
-
source: 'https://docs.stripe.com/api/payment_intents/confirm',
|
|
32
|
-
})),
|
|
33
|
-
// a bank debit confirmed (created with `confirm`, confirmed, or verified by micro-deposits) is submitted and
|
|
34
|
-
// processes: "The PaymentIntent you create initially has a status of `processing`"; "When the bank account is
|
|
35
|
-
// successfully verified, Stripe returns the PaymentIntent object with a status of `processing`"
|
|
36
|
-
...['PostPaymentIntents', 'PostPaymentIntentsIntentConfirm'].map((operation) => ({
|
|
20
|
+
// a bank debit confirmed (created with `confirm`, or confirmed) is submitted and processes: "The PaymentIntent you
|
|
21
|
+
// create initially has a status of `processing`"
|
|
22
|
+
...['PostPaymentIntents',].map((operation) => ({
|
|
37
23
|
operation, from: ['requires_payment_method', 'requires_confirmation', 'requires_action'], to: 'processing',
|
|
38
24
|
source: 'https://docs.stripe.com/payments/ach-direct-debit/accept-a-payment?payment-ui=direct-api',
|
|
39
25
|
})),
|
|
@@ -48,33 +34,10 @@ const paymentIntentStatus = {
|
|
|
48
34
|
source: 'spec:PostPaymentIntents "Set to `true` to attempt to [confirm this PaymentIntent](https://docs.stripe.com/api/payment_intents/confirm) immediately."',
|
|
49
35
|
})),
|
|
50
36
|
{
|
|
51
|
-
operation: '
|
|
52
|
-
from:
|
|
53
|
-
to: 'succeeded',
|
|
54
|
-
refusal: unexpected('captured', 'Only a PaymentIntent with one of the following statuses may be captured: requires_capture.'),
|
|
55
|
-
source: 'https://docs.stripe.com/api/payment_intents/capture',
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
operation: 'PostPaymentIntentsIntentIncrementAuthorization',
|
|
59
|
-
from: ['requires_capture'],
|
|
60
|
-
to: 'requires_capture',
|
|
61
|
-
refusal: unexpected('incremented', 'Only a PaymentIntent with a status of requires_capture may be incremented.'),
|
|
62
|
-
source: 'https://docs.stripe.com/api/payment_intents/increment_authorization',
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
operation: 'PostPaymentIntentsIntentCancel',
|
|
66
|
-
from: OPEN,
|
|
67
|
-
to: 'canceled',
|
|
68
|
-
refusal: unexpected('canceled', 'Only a PaymentIntent with one of the following statuses may be canceled: requires_payment_method, requires_capture, requires_confirmation, requires_action, processing.'),
|
|
37
|
+
operation: 'PostPaymentIntentsIntentCancel', from: OPEN, to: 'canceled',
|
|
38
|
+
refusal: { status: 400, code: 'payment_intent_unexpected_state', message: 'You cannot cancel this PaymentIntent because it has a status of {from}. Only a PaymentIntent with one of the following statuses may be canceled: requires_payment_method, requires_capture, requires_confirmation, requires_action, processing.' },
|
|
69
39
|
source: 'https://docs.stripe.com/api/payment_intents/cancel',
|
|
70
40
|
},
|
|
71
|
-
{
|
|
72
|
-
operation: 'PostPaymentIntentsIntentVerifyMicrodeposits',
|
|
73
|
-
from: ['requires_action'],
|
|
74
|
-
to: 'processing',
|
|
75
|
-
refusal: { status: 400, code: 'payment_intent_unexpected_state', message: 'This PaymentIntent could not be verified because it has a status of {from}.' },
|
|
76
|
-
source: 'https://docs.stripe.com/payments/ach-direct-debit/accept-a-payment?payment-ui=direct-api',
|
|
77
|
-
},
|
|
78
41
|
{
|
|
79
42
|
// paying the invoice an intent collects for settles the intent
|
|
80
43
|
operation: 'PostInvoicesInvoicePay',
|
|
@@ -82,49 +45,30 @@ const paymentIntentStatus = {
|
|
|
82
45
|
to: 'succeeded',
|
|
83
46
|
source: 'https://docs.stripe.com/api/invoices/pay',
|
|
84
47
|
},
|
|
85
|
-
...['succeeded', 'requires_action'].map((to) => ({
|
|
86
|
-
operation: 'PostPaymentIntentsIntentApplyCustomerBalance',
|
|
87
|
-
from: OPEN,
|
|
88
|
-
to,
|
|
89
|
-
refusal: { status: 400, code: 'payment_intent_unexpected_state', message: 'This PaymentIntent could not be updated because it has a status of {from}.' },
|
|
90
|
-
source: 'https://docs.stripe.com/api/payment_intents/apply_customer_balance',
|
|
91
|
-
})),
|
|
92
|
-
// a card presented to the Terminal reader processing an intent pays it (held, under manual capture)
|
|
93
|
-
...['succeeded', 'requires_capture'].map((to) => ({
|
|
94
|
-
operation: 'PostTestHelpersTerminalReadersReaderPresentPaymentMethod', from: ['requires_payment_method', 'requires_confirmation'], to,
|
|
95
|
-
source: 'https://docs.stripe.com/api/terminal/readers/present_payment_method',
|
|
96
|
-
})),
|
|
97
48
|
// the customer pays, in the billing portal, the invoice an intent collects for after its charge was declined
|
|
98
49
|
by('external', ['requires_payment_method'], 'succeeded', 'https://docs.stripe.com/customer-management'),
|
|
99
50
|
// Stripe also fails a bank debit back to needing a payment method, completes 3-D Secure on the bank's page and
|
|
100
51
|
// cancels a hold left uncaptured; the twin's bank debits succeed unless their test account stays processing, it has no 3-D Secure page, and it keeps
|
|
101
|
-
// holds until they are
|
|
52
|
+
// holds until they are canceled. Capture, increment_authorization, verify_microdeposits, apply_customer_balance and
|
|
53
|
+
// the Terminal reader's present_payment_method are the gap (no demand, life step or refresh sends them:
|
|
54
|
+
// ../manifest.ts unmodeled), so no move of theirs is declared.
|
|
102
55
|
],
|
|
103
56
|
};
|
|
104
|
-
/** A charge's `captured`: an authorization (
|
|
57
|
+
/** A charge's `captured`: an authorization (capture_method=manual) is captured once, by the Charges API's capture or
|
|
58
|
+
* its PaymentIntent's; both are the gap here (no demand, life step or refresh sends them: ../manifest.ts unmodeled), so
|
|
59
|
+
* a held charge stays uncaptured until its intent is canceled, and no move is declared. */
|
|
105
60
|
const chargeCaptured = {
|
|
106
61
|
initial: true,
|
|
107
|
-
transitions: [
|
|
108
|
-
{
|
|
109
|
-
operation: 'PostChargesChargeCapture',
|
|
110
|
-
from: ['false'],
|
|
111
|
-
to: 'true',
|
|
112
|
-
refusal: { status: 400, code: 'charge_already_captured', message: 'Charge ch_xxx has already been captured.' },
|
|
113
|
-
source: 'https://docs.stripe.com/api/charges/capture',
|
|
114
|
-
},
|
|
115
|
-
// a manual-capture intent's capture captures the charge its confirm authorized
|
|
116
|
-
{ operation: 'PostPaymentIntentsIntentCapture', from: ['false'], to: 'true', source: 'https://docs.stripe.com/api/payment_intents/capture' },
|
|
117
|
-
],
|
|
62
|
+
transitions: [],
|
|
118
63
|
};
|
|
119
|
-
/** A charge's `refunded`: true once refunds take its whole amount
|
|
120
|
-
* canceled. A capture or a cancel never makes it so: "`refunded` will no longer be `true` for payment cancellation
|
|
64
|
+
/** A charge's `refunded`: true once refunds take its whole amount. A capture or a cancel never makes it so: "`refunded` will no longer be `true` for payment cancellation
|
|
121
65
|
* flows", and a partial capture makes no Refund (docs.stripe.com/changelog/basil/2025-03-31/remove-refund-from-partial-
|
|
122
66
|
* capture-and-payment-cancellation-flow). */
|
|
123
67
|
const chargeRefunded = {
|
|
124
68
|
initial: false,
|
|
125
69
|
transitions: [
|
|
126
|
-
|
|
127
|
-
|
|
70
|
+
{ operation: 'PostRefunds', from: ['false'], to: 'true', source: 'https://docs.stripe.com/api/charges/object#charge_object-refunded' },
|
|
71
|
+
// (a charge's own refunds path, a credit note's refund and a refund's cancel are the gap here: ../manifest.ts unmodeled)
|
|
128
72
|
// (an authorization left uncaptured is canceled after seven days, "Uncaptured PaymentIntents are cancelled a set
|
|
129
73
|
// number of days (7 by default) after their creation", docs.stripe.com/api/payment_intents/capture; the twin keeps it)
|
|
130
74
|
],
|
|
@@ -143,63 +87,26 @@ const chargePaid = {
|
|
|
143
87
|
// (a charge is paid when it settles; the twin's settle when made)
|
|
144
88
|
transitions: [],
|
|
145
89
|
};
|
|
146
|
-
/** A refund's `status`:
|
|
147
|
-
*
|
|
90
|
+
/** A refund's `status`: held pending for want of balance, then made; the rest is the network's. (Canceling one that
|
|
91
|
+
* waits on the customer is the gap here: ../manifest.ts unmodeled.) */
|
|
148
92
|
const refundStatus = {
|
|
149
93
|
initial: 'succeeded',
|
|
150
94
|
transitions: [
|
|
151
|
-
{
|
|
152
|
-
operation: 'PostRefundsRefundCancel',
|
|
153
|
-
from: ['requires_action'],
|
|
154
|
-
to: 'canceled',
|
|
155
|
-
refusal: { status: 400, code: 'refund_status_invalid', message: 'Refund {id} cannot be canceled because its status is {from}.' },
|
|
156
|
-
source: 'https://docs.stripe.com/api/refunds/cancel',
|
|
157
|
-
},
|
|
158
|
-
// a card refund the available balance does not cover is held pending, and made once the balance covers it: "Stripe
|
|
159
|
-
// holds the refund as pending for card transactions ... until your Stripe balance becomes sufficient"
|
|
160
|
-
// (docs.stripe.com/refunds; semantics/refunds.ts)
|
|
161
|
-
// (a paid invoice's credit note makes its refund as a refund call does: "Refunds: create a new refund (using
|
|
162
|
-
// refund_amount)", docs.stripe.com/api/credit_notes/create)
|
|
163
|
-
...['PostRefunds', 'PostChargesChargeRefunds', 'PostCreditNotes'].map((operation) => ({ operation, from: ['succeeded'], to: 'pending', source: 'https://docs.stripe.com/refunds' })),
|
|
95
|
+
{ operation: 'PostRefunds', from: ['succeeded'], to: 'pending', source: 'https://docs.stripe.com/refunds' },
|
|
164
96
|
by('vendor', ['pending'], 'succeeded', 'https://docs.stripe.com/refunds'),
|
|
165
97
|
// a bank-transfer payment's refund waits in requires_action for the customer's bank details, and is made so
|
|
166
98
|
// (semantics/refunds.ts); (Stripe also fails some refunds; the twin's do not fail)
|
|
167
99
|
],
|
|
168
100
|
};
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
/** A SetupIntent's `status`: confirm settles it (or leaves a bank account awaiting micro-deposits),
|
|
172
|
-
* cancel ends an open one, and verification completes the micro-deposit wait. */
|
|
101
|
+
/** A SetupIntent's `status`: confirm settles it, or leaves a bank account awaiting micro-deposits. (Its cancel and its
|
|
102
|
+
* micro-deposit verification are the gap here: ../manifest.ts unmodeled.) */
|
|
173
103
|
const setupIntentStatus = {
|
|
174
104
|
// "After you create the SetupIntent, it has a status of `requires_payment_method` until you attach a payment method"
|
|
175
105
|
// (docs.stripe.com/payments/paymentintents/lifecycle)
|
|
176
106
|
initial: 'requires_payment_method',
|
|
177
107
|
transitions: [
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
...['requires_action', 'succeeded'].map((to) => ({
|
|
181
|
-
operation: 'PostSetupIntentsIntentConfirm',
|
|
182
|
-
from: SETUP_OPEN,
|
|
183
|
-
to,
|
|
184
|
-
refusal: setupUnexpected('confirm'),
|
|
185
|
-
source: 'https://docs.stripe.com/api/setup_intents/confirm',
|
|
186
|
-
})),
|
|
187
|
-
{
|
|
188
|
-
operation: 'PostSetupIntentsIntentCancel',
|
|
189
|
-
from: SETUP_OPEN,
|
|
190
|
-
to: 'canceled',
|
|
191
|
-
refusal: setupUnexpected('cancel'),
|
|
192
|
-
source: 'https://docs.stripe.com/api/setup_intents/cancel',
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
operation: 'PostSetupIntentsIntentVerifyMicrodeposits',
|
|
196
|
-
from: ['requires_action'],
|
|
197
|
-
to: 'succeeded',
|
|
198
|
-
refusal: { status: 400, code: 'setup_intent_unexpected_state', message: 'This SetupIntent could not be verified because it has a status of {from}.' },
|
|
199
|
-
source: 'https://docs.stripe.com/api/setup_intents/verify_microdeposits',
|
|
200
|
-
},
|
|
201
|
-
// (Stripe completes 3-D Secure on the bank's page and settles an asynchronous method from processing; the
|
|
202
|
-
// twin has no such page and settles every method at once)
|
|
108
|
+
// (Stripe completes 3-D Secure on the bank's page and settles an asynchronous method from processing; the
|
|
109
|
+
// twin has no such page and settles every method at once)
|
|
203
110
|
],
|
|
204
111
|
};
|
|
205
112
|
const invoiceRefusal = (message) => ({ status: 400, code: 'invoice_not_editable', message });
|
|
@@ -208,38 +115,20 @@ const invoiceRefusal = (message) => ({ status: 400, code: 'invoice_not_editable'
|
|
|
208
115
|
const invoiceStatus = {
|
|
209
116
|
initial: 'draft',
|
|
210
117
|
transitions: [
|
|
118
|
+
{ operation: 'PostInvoicesInvoicePay', from: ['draft'], to: 'open', source: 'https://docs.stripe.com/invoicing/integration' },
|
|
211
119
|
{
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
to: 'open',
|
|
215
|
-
refusal: invoiceRefusal('This invoice cannot be finalized because it has status {from}.'),
|
|
216
|
-
source: 'https://docs.stripe.com/api/invoices/finalize',
|
|
217
|
-
},
|
|
218
|
-
// docs.stripe.com/invoicing/integration: "To finalize a draft invoice, use the Dashboard, send it to the customer, or pay it."
|
|
219
|
-
{ operation: 'PostInvoicesInvoiceSend', from: ['draft'], to: 'open', source: 'https://docs.stripe.com/invoicing/integration' },
|
|
220
|
-
{ operation: 'PostInvoicesInvoiceSend', from: ['open', 'paid', 'uncollectible', 'void'], source: 'https://docs.stripe.com/api/invoices/send' },
|
|
221
|
-
{
|
|
120
|
+
// paying a draft finalizes it on the way: "To finalize a draft invoice, use the Dashboard, send it to the customer, or
|
|
121
|
+
// pay it" (docs.stripe.com/invoicing/integration)
|
|
222
122
|
operation: 'PostInvoicesInvoicePay',
|
|
223
|
-
from: ['open', 'uncollectible'],
|
|
123
|
+
from: ['draft', 'open', 'uncollectible'],
|
|
224
124
|
to: 'paid',
|
|
225
125
|
refusal: invoiceRefusal('This invoice cannot be paid because it has status {from}.'),
|
|
226
126
|
refusals: { paid: { status: 400, code: 'invoice_payment_intent_requires_action', message: 'This invoice has already been paid.' } },
|
|
227
127
|
source: 'https://docs.stripe.com/api/invoices/pay',
|
|
228
128
|
},
|
|
229
|
-
|
|
230
|
-
operation: 'PostInvoicesInvoiceMarkUncollectible',
|
|
231
|
-
from: ['open'],
|
|
232
|
-
to: 'uncollectible',
|
|
233
|
-
refusal: invoiceRefusal('Only open invoices can be marked uncollectible (this one is {from}).'),
|
|
234
|
-
source: 'https://docs.stripe.com/api/invoices/mark_uncollectible',
|
|
235
|
-
},
|
|
129
|
+
// (marking one uncollectible is the gap here: ../manifest.ts unmodeled)
|
|
236
130
|
// a guard: only a draft is deleted; a finalized invoice is voided instead
|
|
237
|
-
|
|
238
|
-
operation: 'DeleteInvoicesInvoice',
|
|
239
|
-
from: ['draft'],
|
|
240
|
-
refusal: invoiceRefusal('You can only delete draft invoices.'),
|
|
241
|
-
source: 'https://docs.stripe.com/api/invoices/delete',
|
|
242
|
-
},
|
|
131
|
+
// in any other state it is refused (a refusal with no `to` refuses where it stands)
|
|
243
132
|
{
|
|
244
133
|
// only a finalized invoice is voided; a draft is deleted
|
|
245
134
|
operation: 'PostInvoicesInvoiceVoid',
|
|
@@ -248,15 +137,11 @@ const invoiceStatus = {
|
|
|
248
137
|
refusal: invoiceRefusal('This invoice cannot be voided because it has status {from}.'),
|
|
249
138
|
source: 'https://docs.stripe.com/api/invoices/void',
|
|
250
139
|
},
|
|
251
|
-
// confirming
|
|
252
|
-
...['PostPaymentIntentsIntentConfirm', 'PostPaymentIntentsIntentCapture'].map((operation) => ({
|
|
253
|
-
operation, from: ['draft', 'open', 'uncollectible'], to: 'paid', source: 'https://docs.stripe.com/billing/subscriptions/build-subscriptions',
|
|
254
|
-
})),
|
|
140
|
+
// confirming the PaymentIntent an invoice collects through pays the invoice
|
|
255
141
|
// as does its bank debit succeeding once submitted (../engine/payment-intents.ts settleBankDebits)
|
|
256
142
|
by('vendor', ['draft', 'open', 'uncollectible'], 'paid', 'https://docs.stripe.com/billing/subscriptions/build-subscriptions'),
|
|
257
|
-
// a bank transfer
|
|
258
|
-
//
|
|
259
|
-
{ operation: 'PostTestHelpersCustomersCustomerFundCashBalance', from: ['open'], to: 'paid', source: 'https://docs.stripe.com/payments/customer-balance/reconciliation' },
|
|
143
|
+
// (a bank transfer reconciled from the customer's cash balance pays one at Stripe; funding a cash balance is the gap
|
|
144
|
+
// here: ../manifest.ts unmodeled)
|
|
260
145
|
// a subscription's first invoice is paid on the Checkout page that started it
|
|
261
146
|
by('external', ['draft'], 'paid', 'https://docs.stripe.com/payments/checkout/how-checkout-works'),
|
|
262
147
|
// a subscription's renewal, drafted at its period's end, is finalized about an hour later and charged: paid, or
|
|
@@ -268,7 +153,6 @@ const invoiceStatus = {
|
|
|
268
153
|
{ operation: 'PostSubscriptionsSubscriptionExposedId', from: ['draft'], to: 'paid', source: 'https://docs.stripe.com/billing/subscriptions/upgrade-downgrade#immediate-payment' },
|
|
269
154
|
// a trialing subscription's first invoice, for nothing, is paid as it is made ("An immediate invoice is still
|
|
270
155
|
// created, but the amount is 0", docs.stripe.com/billing/subscriptions/trials/free-trials)
|
|
271
|
-
{ operation: 'PostSubscriptions', from: ['draft'], to: 'paid', source: 'https://docs.stripe.com/billing/subscriptions/trials/free-trials' },
|
|
272
156
|
{ operation: 'PostSubscriptionsSubscriptionExposedId', from: ['draft'], to: 'open', source: 'https://docs.stripe.com/billing/subscriptions/upgrade-downgrade#immediate-payment' },
|
|
273
157
|
// the customer pays an open invoice in the billing portal
|
|
274
158
|
by('external', ['open'], 'paid', 'https://docs.stripe.com/customer-management'),
|
|
@@ -284,16 +168,8 @@ const subscriptionStatus = {
|
|
|
284
168
|
{ operation: 'DeleteSubscriptionsSubscriptionExposedId', from: '*', to: 'canceled', source: 'https://docs.stripe.com/api/subscriptions/cancel' },
|
|
285
169
|
// (a test clock's advance moves no subscription itself: when the clock reaches its target, a trial that ended there
|
|
286
170
|
// ends by time's move below, on the next request; ../engine/test-clocks.ts finishClockAdvances)
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
{ operation: 'DeleteTestHelpersTestClocksTestClock', from: '*', to: 'canceled', source: 'https://docs.stripe.com/billing/testing/test-clocks/api-advanced-usage' },
|
|
290
|
-
// "Cancels a subscription schedule and its associated subscription immediately" (docs.stripe.com/api/subscription_schedules/cancel)
|
|
291
|
-
{ operation: 'PostSubscriptionSchedulesScheduleCancel', from: ['active', 'trialing', 'past_due', 'incomplete'], to: 'canceled', source: 'https://docs.stripe.com/api/subscription_schedules/cancel' },
|
|
292
|
-
// confirming or capturing the first invoice's PaymentIntent, or paying the invoice itself, pays it and
|
|
293
|
-
// activates the subscription
|
|
294
|
-
...['PostPaymentIntentsIntentConfirm', 'PostPaymentIntentsIntentCapture'].map((operation) => ({
|
|
295
|
-
operation, from: ['incomplete'], to: 'active', source: 'https://docs.stripe.com/billing/subscriptions/build-subscriptions',
|
|
296
|
-
})),
|
|
171
|
+
// (canceling a subscription schedule, which cancels its subscription, is the gap here: ../manifest.ts unmodeled)
|
|
172
|
+
// confirming the first invoice's PaymentIntent, or paying the invoice itself, pays it and activates the subscription
|
|
297
173
|
// or when its bank debit succeeds once submitted (../engine/payment-intents.ts settleBankDebits)
|
|
298
174
|
by('vendor', ['incomplete'], 'active', 'https://docs.stripe.com/billing/subscriptions/build-subscriptions'),
|
|
299
175
|
// paying the invoice a subscription waits on (its first, or a renewal that failed) makes it active
|
|
@@ -332,7 +208,6 @@ const notOpen = (verb) => ({ status: 400, code: 'checkout_session_not_open', mes
|
|
|
332
208
|
const checkoutStatus = {
|
|
333
209
|
initial: 'open',
|
|
334
210
|
transitions: [
|
|
335
|
-
{ operation: 'PostCheckoutSessionsSessionExpire', from: ['open'], to: 'expired', refusal: notOpen('expire'), source: 'https://docs.stripe.com/api/checkout/sessions/expire' },
|
|
336
211
|
{ actor: 'external', from: ['open'], to: 'complete', refusal: notOpen('complete'), source: 'https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-status' },
|
|
337
212
|
// (Stripe expires an open session at expires_at; the twin keeps it open until asked)
|
|
338
213
|
],
|
|
@@ -346,73 +221,48 @@ const checkoutPaymentStatus = {
|
|
|
346
221
|
// (a delayed method settles a session later at Stripe; the twin's settle on the page)
|
|
347
222
|
],
|
|
348
223
|
};
|
|
349
|
-
/** A dispute's `status`:
|
|
350
|
-
*
|
|
224
|
+
/** A dispute's `status`: a disputed test card's charge opens one (needs_response, or warning_needs_response for an
|
|
225
|
+
* inquiry). Submitting evidence and closing (conceding) are the gap here (../manifest.ts unmodeled), so nothing puts a
|
|
226
|
+
* dispute under review for the bank to decide; the bank escalates an inquiry and loses one left unanswered at
|
|
227
|
+
* Stripe, and the twin decides none. */
|
|
351
228
|
const disputeStatus = {
|
|
352
229
|
initial: 'warning_needs_response',
|
|
353
|
-
transitions: [
|
|
354
|
-
{ operation: 'PostDisputesDisputeClose', from: '*', to: 'lost', source: 'https://docs.stripe.com/api/disputes/close' },
|
|
355
|
-
// submitting evidence puts a dispute (or an inquiry) under review; in test mode the evidence decides it
|
|
356
|
-
{ operation: 'PostDisputesDispute', from: ['needs_response'], to: 'under_review', source: 'https://docs.stripe.com/api/disputes/update#update_dispute-submit' },
|
|
357
|
-
{ operation: 'PostDisputesDispute', from: ['warning_needs_response'], to: 'warning_under_review', source: 'https://docs.stripe.com/api/disputes/update#update_dispute-submit' },
|
|
358
|
-
by('vendor', ['under_review'], 'won', 'https://docs.stripe.com/testing#evidence'),
|
|
359
|
-
by('vendor', ['under_review'], 'lost', 'https://docs.stripe.com/testing#evidence'),
|
|
360
|
-
// (the bank decides a dispute under review, escalates an inquiry and loses one left unanswered; the twin
|
|
361
|
-
// decides none)
|
|
362
|
-
// Stripe also closes an inquiry the bank drops (warning_closed); no inquiry the twin holds is dropped
|
|
363
|
-
],
|
|
230
|
+
transitions: [],
|
|
364
231
|
};
|
|
365
232
|
/** A payout's `status`: cancel ends it; reversing cancels it and pays a reversal, never twice. */
|
|
366
233
|
const payoutStatus = {
|
|
367
234
|
initial: 'pending',
|
|
368
235
|
transitions: [
|
|
369
|
-
//
|
|
370
|
-
// payout and leaves the original paid (semantics/balance.ts)
|
|
371
|
-
{ operation: 'PostPayoutsPayoutCancel', from: ['pending'], to: 'canceled', source: 'https://docs.stripe.com/api/payouts/cancel' },
|
|
236
|
+
// (canceling a pending payout and reversing a paid one are the gap here: ../manifest.ts unmodeled)
|
|
372
237
|
// it arrives in the bank on its arrival date
|
|
373
238
|
by('time', ['pending'], 'paid', 'https://docs.stripe.com/payouts#payout-statuses'),
|
|
374
239
|
// (a bank may fail a payout at Stripe; the twin's arrive)
|
|
375
240
|
],
|
|
376
241
|
};
|
|
377
|
-
/** A credit note's `status`: issued, then voided once.
|
|
242
|
+
/** A credit note's `status`: issued, then voided once at Stripe. Issuing and voiding one are the gap here
|
|
243
|
+
* (../manifest.ts unmodeled): a vendor-backed World reads credit notes back from its root (GetCreditNotes). */
|
|
378
244
|
const creditNoteStatus = {
|
|
379
245
|
initial: 'issued',
|
|
380
|
-
transitions: [
|
|
381
|
-
{
|
|
382
|
-
operation: 'PostCreditNotesIdVoid',
|
|
383
|
-
from: ['issued'],
|
|
384
|
-
to: 'void',
|
|
385
|
-
refusal: { status: 400, code: 'credit_note_already_voided', message: 'This credit note has already been voided.' },
|
|
386
|
-
source: 'https://docs.stripe.com/api/credit_notes/void',
|
|
387
|
-
},
|
|
388
|
-
],
|
|
246
|
+
transitions: [],
|
|
389
247
|
};
|
|
390
|
-
|
|
391
|
-
|
|
248
|
+
/** A subscription schedule's `status`: releasing ends it, and an ended one refuses it. (Canceling one is the gap here:
|
|
249
|
+
* ../manifest.ts unmodeled.) */
|
|
392
250
|
const scheduleStatus = {
|
|
393
251
|
initial: 'active',
|
|
394
252
|
transitions: [
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
// (a schedule whose end_behavior is cancel completes at its end at Stripe; the twin's release)
|
|
401
|
-
// (Stripe starts a schedule at its start date and ends it with its last phase; the twin's start at once
|
|
402
|
-
// and end when canceled or released)
|
|
253
|
+
// "A schedule can only be released if its status is not_started or active" (the release page)
|
|
254
|
+
// its phases run on the clock: it starts at its start date and ends with its last phase
|
|
255
|
+
// (a schedule whose end_behavior is cancel completes at its end at Stripe; the twin's release)
|
|
256
|
+
// (Stripe starts a schedule at its start date and ends it with its last phase; the twin's start at once
|
|
257
|
+
// and end when canceled or released)
|
|
403
258
|
],
|
|
404
259
|
};
|
|
405
|
-
|
|
406
|
-
|
|
260
|
+
/** A quote's `status`: at Stripe a draft is finalized into open, an open one accepted, and either canceled. Quotes are
|
|
261
|
+
* the gap here (../manifest.ts unmodeled): a vendor-backed World reads them back from its root (GetQuotes), so no
|
|
262
|
+
* move is the twin's. */
|
|
407
263
|
const quoteStatus = {
|
|
408
264
|
initial: 'draft',
|
|
409
|
-
transitions: [
|
|
410
|
-
{ operation: 'PostQuotesQuoteFinalize', from: ['draft'], to: 'open', refusal: quoteRefusal('finalized'), source: 'https://docs.stripe.com/api/quotes/finalize' },
|
|
411
|
-
{ operation: 'PostQuotesQuoteAccept', from: ['open'], to: 'accepted', refusal: quoteRefusal('accepted'), source: 'https://docs.stripe.com/api/quotes/accept' },
|
|
412
|
-
{ operation: 'PostQuotesQuoteCancel', from: ['draft', 'open'], to: 'canceled', refusal: quoteRefusal('canceled'), source: 'https://docs.stripe.com/api/quotes/cancel' },
|
|
413
|
-
// an open quote not accepted by its expires_at is canceled
|
|
414
|
-
// (Stripe cancels an open quote at its expires_at; the twin keeps it open)
|
|
415
|
-
],
|
|
265
|
+
transitions: [],
|
|
416
266
|
};
|
|
417
267
|
const setBy = (operation, values, source) => values.map((to) => ({ operation, from: '*', to, source }));
|
|
418
268
|
/** An Issuing authorization's `status`: approve and decline close a pending one, once; a capture
|
|
@@ -421,7 +271,9 @@ const issuingAuthorizationStatus = {
|
|
|
421
271
|
initial: 'pending',
|
|
422
272
|
transitions: [
|
|
423
273
|
// approving keeps it pending (approved) until the merchant captures; declining closes it
|
|
424
|
-
{ operation: 'PostIssuingAuthorizationsAuthorizationApprove', from: ['pending'],
|
|
274
|
+
{ operation: 'PostIssuingAuthorizationsAuthorizationApprove', from: ['pending'], source: 'https://docs.stripe.com/issuing/purchases/authorizations' },
|
|
275
|
+
// in any other state it is refused (a refusal with no `to` refuses where it stands)
|
|
276
|
+
{ operation: 'PostIssuingAuthorizationsAuthorizationApprove', from: '*', refusal: { status: 400, code: 'authorization_already_finalized', message: 'This authorization has already been finalized (status {from}).' }, source: 'https://docs.stripe.com/issuing/purchases/authorizations' },
|
|
425
277
|
{ operation: 'PostIssuingAuthorizationsAuthorizationDecline', from: ['pending'], to: 'closed', refusal: { status: 400, code: 'authorization_already_finalized', message: 'This authorization has already been finalized (status {from}).' }, source: 'https://docs.stripe.com/api/issuing/authorizations/decline' },
|
|
426
278
|
{ operation: 'PostTestHelpersIssuingAuthorizationsAuthorizationCapture', from: ['pending'], to: 'closed', source: 'https://docs.stripe.com/api/issuing/authorizations/test_mode_capture' },
|
|
427
279
|
{ operation: 'PostTestHelpersIssuingAuthorizationsAuthorizationCapture', from: ['pending'], source: 'https://docs.stripe.com/api/issuing/authorizations/test_mode_capture' },
|
|
@@ -433,34 +285,22 @@ const issuingAuthorizationStatus = {
|
|
|
433
285
|
// capture helper above closes it, and the twin serves no other)
|
|
434
286
|
],
|
|
435
287
|
};
|
|
436
|
-
/** A Treasury flow's `status
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
{ operation, from: ['processing'], to: 'canceled', refusal: { status: 400, code, message: `This ${name} cannot be canceled because it is no longer processing.` }, source: 'https://docs.stripe.com/api/treasury' },
|
|
441
|
-
...network,
|
|
442
|
-
],
|
|
443
|
-
});
|
|
444
|
-
/** An outbound flow on the network: Stripe posts or fails it and a posted one may come back returned (in
|
|
445
|
-
* test mode by test helpers the twin does not serve), so none of those moves is the twin's. */
|
|
446
|
-
const outbound = (_doc) => [];
|
|
288
|
+
/** A Treasury flow's `status`: at Stripe a processing flow cancels, the network posts or fails it, and a posted one may
|
|
289
|
+
* come back returned. Treasury's flows are the gap here (../manifest.ts unmodeled): a vendor-backed World reads them
|
|
290
|
+
* back from its root, so no move is the twin's. */
|
|
291
|
+
const flow = { initial: 'processing', transitions: [] };
|
|
447
292
|
export const states = {
|
|
448
293
|
'billing.meter': {
|
|
449
294
|
notState: ['event_time_window'],
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
{ operation: 'PostBillingMetersIdReactivate', from: '*', to: 'active', source: 'https://docs.stripe.com/api/billing/meter/reactivate' },
|
|
453
|
-
] } },
|
|
295
|
+
// (deactivating and reactivating a meter are the gap here: ../manifest.ts unmodeled)
|
|
296
|
+
state: { status: { initial: 'active', transitions: [] } },
|
|
454
297
|
},
|
|
455
298
|
'billing.credit_grant': {
|
|
456
299
|
notState: ['category'],
|
|
457
300
|
},
|
|
458
301
|
'billing.alert': {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
{ operation: 'PostBillingAlertsIdDeactivate', from: '*', to: 'inactive', source: 'https://docs.stripe.com/api/billing/alert/deactivate' },
|
|
462
|
-
{ operation: 'PostBillingAlertsIdArchive', from: '*', to: 'archived', source: 'https://docs.stripe.com/api/billing/alert/archive' },
|
|
463
|
-
] } },
|
|
302
|
+
// (activating, deactivating and archiving an alert are the gap here: ../manifest.ts unmodeled)
|
|
303
|
+
state: { status: { initial: 'active', transitions: [] } },
|
|
464
304
|
},
|
|
465
305
|
payment_intent: {
|
|
466
306
|
state: { status: paymentIntentStatus },
|
|
@@ -523,17 +363,10 @@ export const states = {
|
|
|
523
363
|
notState: ['billing_address_collection', 'customer_creation', 'locale', 'mode', 'origin_context', 'payment_method_collection', 'redirect_on_completion', 'submit_type', 'ui_mode'],
|
|
524
364
|
},
|
|
525
365
|
mandate: {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
// a single-use mandate is spent by its payment: inactive "The mandate was rejected, revoked, or previously
|
|
531
|
-
// used, and may not be used to initiate future payments" (../engine/payment-intents.ts settleBankDebits)
|
|
532
|
-
by('vendor', ['active'], 'inactive', 'https://docs.stripe.com/api/mandates/object'),
|
|
533
|
-
// (Stripe also activates a pending mandate and deactivates one revoked; the twin's are active when made)
|
|
534
|
-
],
|
|
535
|
-
},
|
|
536
|
-
},
|
|
366
|
+
// Stripe activates a pending mandate, spends a single-use one with its payment and deactivates one revoked; the twin
|
|
367
|
+
// makes no mandate (micro-deposit verification, which accepts one, is the gap here: ../manifest.ts unmodeled), so no
|
|
368
|
+
// move is the twin's
|
|
369
|
+
state: { status: { initial: 'active', transitions: [] } },
|
|
537
370
|
notState: ['type'],
|
|
538
371
|
},
|
|
539
372
|
dispute: {
|
|
@@ -571,7 +404,8 @@ export const states = {
|
|
|
571
404
|
notState: ['end_behavior'],
|
|
572
405
|
},
|
|
573
406
|
'entitlements.feature': {
|
|
574
|
-
|
|
407
|
+
// (updating a feature, which "permanently" deactivates it, is the gap here: ../manifest.ts unmodeled)
|
|
408
|
+
state: { active: { initial: true, transitions: [] } },
|
|
575
409
|
},
|
|
576
410
|
'test_helpers.test_clock': {
|
|
577
411
|
state: {
|
|
@@ -580,7 +414,6 @@ export const states = {
|
|
|
580
414
|
transitions: [
|
|
581
415
|
// "advancing: The clock has started to advance but hasn't reached the specified time"; "ready: The clock has
|
|
582
416
|
// completed advancing to the specified time" (docs.stripe.com/billing/testing/test-clocks/api-advanced-usage)
|
|
583
|
-
{ operation: 'PostTestHelpersTestClocksTestClockAdvance', from: ['ready'], to: 'advancing', refusal: { status: 400, code: 'test_clock_not_ready', message: 'This test clock is still advancing.' }, source: 'https://docs.stripe.com/api/test_clocks/advance' },
|
|
584
417
|
by('vendor', ['advancing'], 'ready', 'https://docs.stripe.com/billing/testing/test-clocks/api-advanced-usage'),
|
|
585
418
|
// (Stripe may also end an advance in internal_failure; the twin's advances complete)
|
|
586
419
|
],
|
|
@@ -588,14 +421,8 @@ export const states = {
|
|
|
588
421
|
},
|
|
589
422
|
},
|
|
590
423
|
webhook_endpoint: {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
initial: 'enabled',
|
|
594
|
-
transitions: [
|
|
595
|
-
...['enabled', 'disabled'].map((to) => ({ operation: 'PostWebhookEndpointsWebhookEndpoint', from: '*', to, source: 'https://docs.stripe.com/api/webhook_endpoints/update#update_webhook_endpoint-disabled' })),
|
|
596
|
-
],
|
|
597
|
-
},
|
|
598
|
-
},
|
|
424
|
+
// (disabling and enabling an endpoint by its update is the gap here: ../manifest.ts unmodeled)
|
|
425
|
+
state: { status: { initial: 'enabled', transitions: [] } },
|
|
599
426
|
},
|
|
600
427
|
account: {
|
|
601
428
|
notState: ['business_type', 'type'],
|
|
@@ -608,10 +435,8 @@ export const states = {
|
|
|
608
435
|
status: {
|
|
609
436
|
initial: 'unrequested',
|
|
610
437
|
transitions: [
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
by('vendor', ['pending', 'inactive'], 'active', 'https://docs.stripe.com/connect/account-capabilities#capability-status'),
|
|
614
|
-
by('vendor', ['active', 'pending'], 'inactive', 'https://docs.stripe.com/connect/account-capabilities#capability-status'),
|
|
438
|
+
// (requesting or unrequesting a capability by its update is the gap here: ../manifest.ts unmodeled)
|
|
439
|
+
// Stripe reviews the account's requirements
|
|
615
440
|
],
|
|
616
441
|
},
|
|
617
442
|
},
|
|
@@ -622,25 +447,17 @@ export const states = {
|
|
|
622
447
|
},
|
|
623
448
|
application_fee: {
|
|
624
449
|
state: { refunded: { initial: false, transitions: [
|
|
625
|
-
{ operation: '
|
|
626
|
-
// a refund of its charge with refund_application_fee refunds it in proportion
|
|
627
|
-
...['PostRefunds', 'PostChargesChargeRefunds'].map((operation) => ({ operation, from: ['false'], to: 'true', source: 'https://docs.stripe.com/api/refunds/create#create_refund-refund_application_fee' })),
|
|
450
|
+
{ operation: 'PostRefunds', from: ['false'], to: 'true', source: 'https://docs.stripe.com/connect/destination-charges#issue-refunds' },
|
|
628
451
|
] } },
|
|
629
452
|
},
|
|
630
453
|
file: {
|
|
631
454
|
notState: ['purpose'],
|
|
632
455
|
},
|
|
633
456
|
'identity.verification_session': {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
by('external', ['requires_input'], 'processing', 'https://docs.stripe.com/identity/how-sessions-work'),
|
|
639
|
-
by('vendor', ['processing'], 'verified', 'https://docs.stripe.com/identity/how-sessions-work'),
|
|
640
|
-
by('vendor', ['processing'], 'requires_input', 'https://docs.stripe.com/identity/how-sessions-work'),
|
|
641
|
-
],
|
|
642
|
-
},
|
|
643
|
-
},
|
|
457
|
+
// the person verifies on Stripe's hosted page, and Stripe decides (docs.stripe.com/identity/how-sessions-work);
|
|
458
|
+
// sessions are the gap here (../manifest.ts unmodeled) and a vendor-backed World reads them back from its root,
|
|
459
|
+
// so no move is the twin's
|
|
460
|
+
state: { status: { initial: 'requires_input', transitions: [] } },
|
|
644
461
|
notState: ['type'],
|
|
645
462
|
},
|
|
646
463
|
'identity.verification_report': {
|
|
@@ -650,11 +467,12 @@ export const states = {
|
|
|
650
467
|
notState: ['locale'],
|
|
651
468
|
},
|
|
652
469
|
'billing_portal.configuration': {
|
|
653
|
-
state: { active: { initial: true, transitions:
|
|
470
|
+
state: { active: { initial: true, transitions: [] } },
|
|
654
471
|
notState: ['is_default'],
|
|
655
472
|
},
|
|
656
473
|
tax_rate: {
|
|
657
|
-
|
|
474
|
+
// (archiving a rate by its update is the gap here: ../manifest.ts unmodeled)
|
|
475
|
+
state: { active: { initial: true, transitions: [] } },
|
|
658
476
|
notState: ['jurisdiction_level', 'rate_type', 'state', 'tax_type'],
|
|
659
477
|
},
|
|
660
478
|
'tax.settings': {
|
|
@@ -671,7 +489,8 @@ export const states = {
|
|
|
671
489
|
notState: ['type'],
|
|
672
490
|
},
|
|
673
491
|
payment_link: {
|
|
674
|
-
|
|
492
|
+
// (switching a link off by its update is the gap here: ../manifest.ts unmodeled)
|
|
493
|
+
state: { active: { initial: true, transitions: [] } },
|
|
675
494
|
notState: ['billing_address_collection', 'customer_creation', 'payment_method_collection', 'submit_type'],
|
|
676
495
|
},
|
|
677
496
|
quote: {
|
|
@@ -679,26 +498,22 @@ export const states = {
|
|
|
679
498
|
notState: ['collection_method'],
|
|
680
499
|
},
|
|
681
500
|
review: {
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
transitions: [
|
|
686
|
-
// (Stripe also closes one when the payment is refunded or disputed; the twin's close only on approval)
|
|
687
|
-
{ operation: 'PostReviewsReviewApprove', from: ['true'], to: 'false', refusal: { status: 400, code: 'review_already_closed', message: 'This review has already been closed.' }, source: 'https://docs.stripe.com/api/radar/reviews/approve' },
|
|
688
|
-
],
|
|
689
|
-
},
|
|
690
|
-
},
|
|
501
|
+
// an elevated-risk card's charge opens one (shared.ts openReview); approving it is the gap here (../manifest.ts
|
|
502
|
+
// unmodeled), and Stripe closes one when the payment is refunded or disputed, which the twin does not
|
|
503
|
+
state: { open: { initial: true, transitions: [] } },
|
|
691
504
|
notState: ['closed_reason', 'opened_reason'],
|
|
692
505
|
},
|
|
693
506
|
'radar.value_list': {
|
|
694
507
|
notState: ['item_type'],
|
|
695
508
|
},
|
|
696
509
|
'issuing.cardholder': {
|
|
697
|
-
|
|
510
|
+
// (a cardholder's status set by its update is the gap here: ../manifest.ts unmodeled)
|
|
511
|
+
state: { status: { initial: 'active', transitions: [] } },
|
|
698
512
|
notState: ['type'],
|
|
699
513
|
},
|
|
700
514
|
'issuing.card': {
|
|
701
|
-
|
|
515
|
+
// a card is made inactive unless its create names a status: "Defaults to inactive" (docs.stripe.com/api/issuing/cards/create)
|
|
516
|
+
state: { status: { initial: 'inactive', transitions: setBy('PostIssuingCardsCard', ['active', 'inactive', 'canceled'], 'https://docs.stripe.com/api/issuing/cards/update') } },
|
|
702
517
|
notState: ['cancellation_reason', 'replacement_reason', 'type'],
|
|
703
518
|
},
|
|
704
519
|
'issuing.authorization': {
|
|
@@ -709,34 +524,15 @@ export const states = {
|
|
|
709
524
|
notState: ['type', 'wallet'],
|
|
710
525
|
},
|
|
711
526
|
'issuing.dispute': {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
transitions: [
|
|
716
|
-
{ operation: 'PostIssuingDisputesDisputeSubmit', from: ['unsubmitted'], to: 'submitted', refusal: { status: 400, code: 'dispute_unsubmitted_required', message: 'This dispute has already been submitted (status {from}).' }, source: 'spec:PostIssuingDisputesDisputeSubmit "Submits an Issuing <code>Dispute</code> to the card network."' },
|
|
717
|
-
// (Stripe decides a submitted dispute won or lost and expires one never submitted; the twin decides none)
|
|
718
|
-
],
|
|
719
|
-
},
|
|
720
|
-
},
|
|
527
|
+
// (submitting one to the network is the gap here, ../manifest.ts unmodeled, and Stripe decides a submitted dispute
|
|
528
|
+
// won or lost and expires one never submitted: a vendor-backed World reads them back from its root)
|
|
529
|
+
state: { status: { initial: 'unsubmitted', transitions: [] } },
|
|
721
530
|
notState: ['loss_reason'],
|
|
722
531
|
},
|
|
723
|
-
'issuing.token': {
|
|
724
|
-
state: { status: { initial: 'active', transitions: [...setBy('PostIssuingTokensToken', ['active', 'deleted', 'suspended'], 'https://docs.stripe.com/api/issuing/tokens/update')] } },
|
|
725
|
-
notState: ['network', 'wallet_provider'],
|
|
726
|
-
},
|
|
727
532
|
'issuing.personalization_design': {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
initial: 'review',
|
|
732
|
-
transitions: [
|
|
733
|
-
...setBy('PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignActivate', ['active'], 'spec:PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignActivate "to <code>active</code>"'),
|
|
734
|
-
...setBy('PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignDeactivate', ['inactive'], 'spec:PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignDeactivate "to <code>inactive</code>"'),
|
|
735
|
-
...setBy('PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignReject', ['rejected'], 'spec:PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignReject "to <code>rejected</code>"'),
|
|
736
|
-
// (outside test mode Stripe's review decides it; the twin is test mode, where these helpers do)
|
|
737
|
-
],
|
|
738
|
-
},
|
|
739
|
-
},
|
|
533
|
+
// a new design waits on Stripe's review (docs.stripe.com/issuing/cards/physical/personalization-design); designs and
|
|
534
|
+
// the test helpers that decide them are the gap here (../manifest.ts unmodeled), read back from a vendor-backed root
|
|
535
|
+
state: { status: { initial: 'review', transitions: [] } },
|
|
740
536
|
},
|
|
741
537
|
'terminal.reader': {
|
|
742
538
|
notState: ['device_type'],
|
|
@@ -753,7 +549,7 @@ export const states = {
|
|
|
753
549
|
// later: "USA (USD) ACH Debit Transfer 5 days" (docs.stripe.com/connect/top-ups; semantics/terminal.ts)
|
|
754
550
|
initial: 'pending',
|
|
755
551
|
transitions: [
|
|
756
|
-
|
|
552
|
+
// (canceling a pending top-up is the gap here: ../manifest.ts unmodeled)
|
|
757
553
|
// to the Issuing balance alike: "Your top-ups can take up to 5 business days to become available"
|
|
758
554
|
// (docs.stripe.com/issuing/funding/balance)
|
|
759
555
|
by('vendor', ['pending'], 'succeeded', 'https://docs.stripe.com/connect/top-ups'),
|
|
@@ -768,17 +564,13 @@ export const states = {
|
|
|
768
564
|
notState: ['is_default'],
|
|
769
565
|
},
|
|
770
566
|
'treasury.outbound_payment': {
|
|
771
|
-
state: { status:
|
|
567
|
+
state: { status: flow },
|
|
772
568
|
},
|
|
773
569
|
'treasury.outbound_transfer': {
|
|
774
|
-
state: { status:
|
|
570
|
+
state: { status: flow },
|
|
775
571
|
},
|
|
776
572
|
'treasury.inbound_transfer': {
|
|
777
|
-
|
|
778
|
-
// been "confirmed""; in test mode the succeed helper confirms them (docs.stripe.com/api/treasury/inbound_transfers)
|
|
779
|
-
state: { status: flowCancel('PostTreasuryInboundTransfersInboundTransferCancel', 'inbound_transfer_not_cancelable', 'InboundTransfer', [
|
|
780
|
-
{ operation: 'PostTestHelpersTreasuryInboundTransfersIdSucceed', from: ['processing'], to: 'succeeded', refusal: { status: 400, code: 'inbound_transfer_not_processing', message: 'This InboundTransfer cannot succeed because it is no longer processing.' }, source: 'https://docs.stripe.com/api/treasury/inbound_transfers' },
|
|
781
|
-
]) },
|
|
573
|
+
state: { status: flow },
|
|
782
574
|
},
|
|
783
575
|
'treasury.received_credit': {
|
|
784
576
|
state: { status: { initial: 'succeeded', transitions: [] } },
|
|
@@ -790,15 +582,9 @@ export const states = {
|
|
|
790
582
|
},
|
|
791
583
|
'treasury.transaction': {
|
|
792
584
|
notState: ['flow_type'],
|
|
793
|
-
//
|
|
794
|
-
//
|
|
795
|
-
|
|
796
|
-
// flow settles; the twin's outbound flows stay processing)
|
|
797
|
-
state: { status: { initial: 'open', transitions: [
|
|
798
|
-
...['PostTreasuryOutboundPaymentsIdCancel', 'PostTreasuryOutboundTransfersOutboundTransferCancel', 'PostTreasuryInboundTransfersInboundTransferCancel'].map((operation) => ({ operation, from: ['open'], to: 'void', source: 'https://docs.stripe.com/api/treasury/transactions/object' })),
|
|
799
|
-
// an inbound transfer's transaction posts when it succeeds ("a transaction is created and posted")
|
|
800
|
-
{ operation: 'PostTestHelpersTreasuryInboundTransfersIdSucceed', from: ['open'], to: 'posted', source: 'https://docs.stripe.com/api/treasury/inbound_transfers' },
|
|
801
|
-
] } },
|
|
585
|
+
// a transaction posts as its flow settles and is voided when its flow is canceled, both Stripe's (the flows are the
|
|
586
|
+
// gap here: ../manifest.ts unmodeled)
|
|
587
|
+
state: { status: { initial: 'open', transitions: [] } },
|
|
802
588
|
},
|
|
803
589
|
'treasury.transaction_entry': {
|
|
804
590
|
notState: ['flow_type', 'type'],
|
|
@@ -809,11 +595,9 @@ export const states = {
|
|
|
809
595
|
// an order is created confirmed: the create page's example answers "status": "confirmed" with confirmed_at set
|
|
810
596
|
// (docs.stripe.com/api/climate/order/create)
|
|
811
597
|
initial: 'confirmed',
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
// (Stripe funds, confirms and delivers an order over months; the twin's orders stay where they are made)
|
|
816
|
-
],
|
|
598
|
+
// (Stripe funds, confirms and delivers an order over months, and cancels one asked to; orders are the gap here,
|
|
599
|
+
// ../manifest.ts unmodeled, read back from a vendor-backed root)
|
|
600
|
+
transitions: [],
|
|
817
601
|
},
|
|
818
602
|
},
|
|
819
603
|
notState: ['cancellation_reason'],
|
|
@@ -822,10 +606,9 @@ export const states = {
|
|
|
822
606
|
state: {
|
|
823
607
|
status: {
|
|
824
608
|
initial: 'active',
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
],
|
|
609
|
+
// (disconnecting one is the gap here, ../manifest.ts unmodeled; Stripe marks an account inactive when the bank
|
|
610
|
+
// link breaks, and active again)
|
|
611
|
+
transitions: [],
|
|
829
612
|
},
|
|
830
613
|
},
|
|
831
614
|
notState: ['category', 'subcategory'],
|
|
@@ -836,17 +619,16 @@ export const states = {
|
|
|
836
619
|
},
|
|
837
620
|
'reporting.report_run': {
|
|
838
621
|
// "When first created, the object appears with status="pending""; "When the run completes, Stripe updates the
|
|
839
|
-
// object, and it has a status of succeeded" (docs.stripe.com/reports/api
|
|
840
|
-
// (
|
|
841
|
-
state: { status: { initial: 'pending', transitions: [
|
|
622
|
+
// object, and it has a status of succeeded" (docs.stripe.com/reports/api). Report runs are the gap here
|
|
623
|
+
// (../manifest.ts unmodeled), read back from a vendor-backed root, so Stripe's move is not the twin's.
|
|
624
|
+
state: { status: { initial: 'pending', transitions: [] } },
|
|
842
625
|
},
|
|
843
626
|
product: {
|
|
844
|
-
state: { active: { initial: true, transitions:
|
|
627
|
+
state: { active: { initial: true, transitions: [] } },
|
|
845
628
|
},
|
|
846
629
|
price: {
|
|
847
630
|
notState: ['billing_scheme', 'tax_behavior', 'tiers_mode', 'type'],
|
|
848
|
-
// deleting a plan leaves its price
|
|
849
|
-
|
|
850
|
-
state: { active: { initial: true, transitions: [...flag('PostPricesPrice', 'https://docs.stripe.com/api/prices/update#update_price-active'), { operation: 'DeletePlansPlan', from: ['true'], to: 'false', source: 'https://docs.stripe.com/api/plans/delete' }] } },
|
|
631
|
+
// (deleting a plan, which leaves its price inactive, is the gap here: ../manifest.ts unmodeled)
|
|
632
|
+
state: { active: { initial: true, transitions: [] } },
|
|
851
633
|
},
|
|
852
634
|
};
|