@volter/twin-stripe 0.1.1 → 2.0.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/README.md +64 -27
- package/client/dashboard-api.ts +286 -0
- package/client/stripe-mirror.css +272 -159
- package/client/stripe-mirror.tsx +1384 -541
- package/dist/client/dashboard-api.d.ts +107 -0
- package/dist/client/dashboard-api.js +238 -0
- package/dist/client/dashboard-api.ts +286 -0
- package/dist/client/stripe-mirror.bundle.js +236 -0
- package/dist/client/stripe-mirror.css +275 -0
- package/dist/client/stripe-mirror.d.ts +134 -0
- package/dist/client/stripe-mirror.js +823 -0
- package/dist/client/stripe-mirror.tsx +1534 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +39 -0
- package/dist/src/generated/events.gen.json +1 -0
- package/dist/src/generated/surface.gen.json +1 -0
- package/dist/src/generated/ui.gen.json +1 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.js +73 -0
- package/dist/src/manifest.d.ts +2 -0
- package/dist/src/manifest.js +1065 -0
- package/dist/src/screens/checkout.d.ts +31 -0
- package/dist/src/screens/checkout.js +241 -0
- package/dist/src/screens/consent-skin.d.ts +4 -0
- package/dist/src/screens/consent-skin.js +18 -0
- package/dist/src/screens/financial-connections.d.ts +5 -0
- package/dist/src/screens/financial-connections.js +90 -0
- package/dist/src/screens/identity.d.ts +5 -0
- package/dist/src/screens/identity.js +86 -0
- package/dist/src/screens/industries.d.ts +1 -0
- package/dist/src/screens/industries.js +267 -0
- package/dist/src/screens/onboarding.d.ts +13 -0
- package/dist/src/screens/onboarding.js +225 -0
- package/dist/src/screens/portal.d.ts +5 -0
- package/dist/src/screens/portal.js +214 -0
- package/dist/src/screens/public-details.d.ts +5 -0
- package/dist/src/screens/public-details.js +90 -0
- package/dist/src/semantics/after-payment.d.ts +22 -0
- package/dist/src/semantics/after-payment.js +93 -0
- package/dist/src/semantics/apps-secrets.d.ts +2 -0
- package/dist/src/semantics/apps-secrets.js +54 -0
- package/dist/src/semantics/balance.d.ts +11 -0
- package/dist/src/semantics/balance.js +195 -0
- package/dist/src/semantics/billing.d.ts +2 -0
- package/dist/src/semantics/billing.js +220 -0
- package/dist/src/semantics/charges.d.ts +28 -0
- package/dist/src/semantics/charges.js +201 -0
- package/dist/src/semantics/checkout.d.ts +15 -0
- package/dist/src/semantics/checkout.js +303 -0
- package/dist/src/semantics/connect.d.ts +5 -0
- package/dist/src/semantics/connect.js +476 -0
- package/dist/src/semantics/coupons.d.ts +6 -0
- package/dist/src/semantics/coupons.js +92 -0
- package/dist/src/semantics/credit-notes.d.ts +2 -0
- package/dist/src/semantics/credit-notes.js +172 -0
- package/dist/src/semantics/customers.d.ts +6 -0
- package/dist/src/semantics/customers.js +429 -0
- package/dist/src/semantics/disputes.d.ts +2 -0
- package/dist/src/semantics/disputes.js +51 -0
- package/dist/src/semantics/entitlements.d.ts +2 -0
- package/dist/src/semantics/entitlements.js +95 -0
- package/dist/src/semantics/ephemeral-keys.d.ts +2 -0
- package/dist/src/semantics/ephemeral-keys.js +34 -0
- package/dist/src/semantics/files.d.ts +2 -0
- package/dist/src/semantics/files.js +125 -0
- package/dist/src/semantics/invoices.d.ts +18 -0
- package/dist/src/semantics/invoices.js +541 -0
- package/dist/src/semantics/issuing.d.ts +13 -0
- package/dist/src/semantics/issuing.js +570 -0
- package/dist/src/semantics/ledger.d.ts +54 -0
- package/dist/src/semantics/ledger.js +181 -0
- package/dist/src/semantics/payment-intents.d.ts +18 -0
- package/dist/src/semantics/payment-intents.js +404 -0
- package/dist/src/semantics/payment-links.d.ts +2 -0
- package/dist/src/semantics/payment-links.js +133 -0
- package/dist/src/semantics/payment-methods.d.ts +20 -0
- package/dist/src/semantics/payment-methods.js +138 -0
- package/dist/src/semantics/plans.d.ts +5 -0
- package/dist/src/semantics/plans.js +121 -0
- package/dist/src/semantics/platform.d.ts +9 -0
- package/dist/src/semantics/platform.js +206 -0
- package/dist/src/semantics/products.d.ts +2 -0
- package/dist/src/semantics/products.js +140 -0
- package/dist/src/semantics/radar.d.ts +2 -0
- package/dist/src/semantics/radar.js +83 -0
- package/dist/src/semantics/refunds.d.ts +9 -0
- package/dist/src/semantics/refunds.js +195 -0
- package/dist/src/semantics/renewals.d.ts +47 -0
- package/dist/src/semantics/renewals.js +251 -0
- package/dist/src/semantics/setup-intents.d.ts +2 -0
- package/dist/src/semantics/setup-intents.js +84 -0
- package/dist/src/semantics/shared.d.ts +78 -0
- package/dist/src/semantics/shared.js +192 -0
- package/dist/src/semantics/subscription-schedules.d.ts +2 -0
- package/dist/src/semantics/subscription-schedules.js +119 -0
- package/dist/src/semantics/subscriptions.d.ts +11 -0
- package/dist/src/semantics/subscriptions.js +605 -0
- package/dist/src/semantics/tax.d.ts +2 -0
- package/dist/src/semantics/tax.js +197 -0
- package/dist/src/semantics/terminal.d.ts +5 -0
- package/dist/src/semantics/terminal.js +182 -0
- package/dist/src/semantics/test-clocks.d.ts +6 -0
- package/dist/src/semantics/test-clocks.js +73 -0
- package/dist/src/semantics/tokens.d.ts +4 -0
- package/dist/src/semantics/tokens.js +44 -0
- package/dist/src/semantics/transfers.d.ts +2 -0
- package/dist/src/semantics/transfers.js +154 -0
- package/dist/src/semantics/treasury.d.ts +2 -0
- package/dist/src/semantics/treasury.js +377 -0
- package/dist/src/semantics/webhook-endpoints.d.ts +3 -0
- package/dist/src/semantics/webhook-endpoints.js +85 -0
- package/dist/src/stripe-budget.d.ts +55 -0
- package/dist/src/stripe-budget.js +155 -0
- package/dist/src/stripe-capabilities.d.ts +3 -0
- package/dist/src/stripe-capabilities.js +5052 -0
- package/dist/src/stripe-conformance.d.ts +41 -0
- package/dist/src/stripe-conformance.js +96 -0
- package/dist/src/stripe-connector.d.ts +161 -0
- package/dist/src/stripe-connector.js +414 -0
- package/dist/src/stripe-emit.d.ts +2 -0
- package/dist/src/stripe-emit.js +145 -0
- package/dist/src/stripe-events.d.ts +93 -0
- package/dist/src/stripe-events.js +388 -0
- package/dist/src/stripe-js.d.ts +4 -0
- package/dist/src/stripe-js.js +70 -0
- package/dist/src/stripe-mirror-ui.d.ts +15 -0
- package/dist/src/stripe-mirror-ui.js +87 -0
- package/dist/src/stripe-params.d.ts +3 -0
- package/dist/src/stripe-params.js +43 -0
- package/dist/src/stripe-perform-harness.d.ts +9 -0
- package/dist/src/stripe-perform-harness.js +26 -0
- package/dist/src/stripe-server.d.ts +33 -0
- package/dist/src/stripe-server.js +326 -0
- package/dist/src/stripe-shared.d.ts +106 -0
- package/dist/src/stripe-shared.js +273 -0
- package/dist/src/stripe-twin.d.ts +155 -0
- package/dist/src/stripe-twin.js +1226 -0
- package/dist/src/stripe-ui-conformance.d.ts +5 -0
- package/dist/src/stripe-ui-conformance.js +79 -0
- package/dist/src/stripe-ui-structure.d.ts +3 -0
- package/dist/src/stripe-ui-structure.js +168 -0
- package/dist/src/stripe-version.d.ts +10 -0
- package/dist/src/stripe-version.js +285 -0
- package/dist/test-fixtures/stripe-known-deviations.json +105 -0
- package/dist/test-fixtures/stripe-openapi-operations.SOURCE.md +14 -0
- package/dist/test-fixtures/stripe-openapi-operations.json +4717 -0
- package/dist/test-fixtures/stripe-schemas.SOURCE.md +35 -0
- package/dist/test-fixtures/stripe-schemas.json +3740 -0
- package/package.json +18 -10
- package/src/cli.ts +7 -7
- package/src/generated/events.gen.json +1 -0
- package/src/generated/surface.gen.json +1 -0
- package/src/generated/ui.gen.json +1 -0
- package/src/index.ts +31 -9
- package/src/manifest.ts +1097 -0
- package/src/screens/checkout.tsx +252 -0
- package/src/screens/consent-skin.ts +20 -0
- package/src/screens/financial-connections.tsx +101 -0
- package/src/screens/identity.tsx +96 -0
- package/src/screens/industries.ts +267 -0
- package/src/screens/onboarding.tsx +243 -0
- package/src/screens/portal.tsx +218 -0
- package/src/screens/public-details.tsx +105 -0
- package/src/semantics/after-payment.ts +113 -0
- package/src/semantics/apps-secrets.ts +58 -0
- package/src/semantics/balance.ts +209 -0
- package/src/semantics/billing.ts +216 -0
- package/src/semantics/charges.ts +211 -0
- package/src/semantics/checkout.ts +297 -0
- package/src/semantics/connect.ts +471 -0
- package/src/semantics/coupons.ts +97 -0
- package/src/semantics/credit-notes.ts +168 -0
- package/src/semantics/customers.ts +432 -0
- package/src/semantics/disputes.ts +62 -0
- package/src/semantics/entitlements.ts +94 -0
- package/src/semantics/ephemeral-keys.ts +34 -0
- package/src/semantics/files.ts +143 -0
- package/src/semantics/invoices.ts +541 -0
- package/src/semantics/issuing.ts +585 -0
- package/src/semantics/ledger.ts +216 -0
- package/src/semantics/payment-intents.ts +420 -0
- package/src/semantics/payment-links.ts +148 -0
- package/src/semantics/payment-methods.ts +143 -0
- package/src/semantics/plans.ts +131 -0
- package/src/semantics/platform.ts +220 -0
- package/src/semantics/products.ts +154 -0
- package/src/semantics/radar.ts +85 -0
- package/src/semantics/refunds.ts +218 -0
- package/src/semantics/renewals.ts +274 -0
- package/src/semantics/setup-intents.ts +87 -0
- package/src/semantics/shared.ts +215 -0
- package/src/semantics/subscription-schedules.ts +129 -0
- package/src/semantics/subscriptions.ts +610 -0
- package/src/semantics/tax.ts +220 -0
- package/src/semantics/terminal.ts +195 -0
- package/src/semantics/test-clocks.ts +77 -0
- package/src/semantics/tokens.ts +52 -0
- package/src/semantics/transfers.ts +174 -0
- package/src/semantics/treasury.ts +383 -0
- package/src/semantics/webhook-endpoints.ts +87 -0
- package/src/stripe-budget.ts +4 -4
- package/src/stripe-capabilities.ts +1456 -222
- package/src/stripe-conformance.ts +6 -5
- package/src/stripe-connector.ts +68 -40
- package/src/stripe-emit.ts +14 -7
- package/src/stripe-events.ts +94 -36
- package/src/stripe-js.ts +70 -0
- package/src/stripe-mirror-ui.ts +28 -298
- package/src/stripe-params.ts +44 -0
- package/src/stripe-perform-harness.ts +29 -0
- package/src/stripe-server.ts +263 -38
- package/src/stripe-shared.ts +294 -0
- package/src/stripe-twin.ts +429 -5325
- package/src/stripe-ui-conformance.ts +70 -107
- package/src/stripe-ui-structure.ts +124 -348
- package/src/stripe-version.ts +278 -0
- package/test-fixtures/stripe-known-deviations.json +2 -7
- package/test-fixtures/stripe-openapi-operations.json +1188 -2855
- package/src/stripe-form.ts +0 -35
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Subscription schedule semantics: a schedule drives a subscription through phases (items for a
|
|
2
|
+
// duration). One made for a customer starts its subscription at once on the first phase's items. Cancel and
|
|
3
|
+
// release end it, the machine's moves in ../manifest.ts. List and update are the derived core's.
|
|
4
|
+
//
|
|
5
|
+
// Where the documentation stops and the twin decides: the subscription a schedule starts raises no first invoice.
|
|
6
|
+
import type { Semantics, SemanticsContext } from '@volter/world-core';
|
|
7
|
+
import { addBillingInterval, buildSubscriptionItemsList } from '../stripe-twin.ts';
|
|
8
|
+
import { at, created, fail, finder, type Row } from './shared.ts';
|
|
9
|
+
import { storeItems } from './subscriptions.ts';
|
|
10
|
+
|
|
11
|
+
const SS = 'subscription_schedule';
|
|
12
|
+
const scheduleMissing = (ctx: SemanticsContext, id: string): Response => fail(ctx, `No such subscription_schedule: '${id}'`, 404, 'resource_missing');
|
|
13
|
+
|
|
14
|
+
type Interval = Parameters<typeof addBillingInterval>[1];
|
|
15
|
+
|
|
16
|
+
/** A schedule's phases as Stripe answers them (the served spec's subscription_schedule_phase_configuration): each
|
|
17
|
+
* starts where the last ended (the first at the schedule's start_date, "now" or a timestamp), and ends at its
|
|
18
|
+
* end_date or after its duration ("duration: interval, interval_count", the served spec's phases[] parameter) on the
|
|
19
|
+
* calendar; its currency is its first price's, each item carries its price, quantity and (empty) discounts. Where the
|
|
20
|
+
* documentation stops and the twin decides: a phase with neither lasts one interval of its first price. */
|
|
21
|
+
function phasesOf(ctx: SemanticsContext, given: Row[], start: number): Row[] {
|
|
22
|
+
let cursor = start;
|
|
23
|
+
return given.map((p) => {
|
|
24
|
+
const items = (Array.isArray(p.items) ? (p.items as Row[]) : []).map((it) => ({ price: it.price ?? null, quantity: Math.max(1, Math.trunc(Number(it.quantity) || 1)), discounts: [], metadata: {}, tax_rates: [], billing_thresholds: null }));
|
|
25
|
+
const price = typeof items[0]?.price === 'string' ? ctx.get('price', items[0]!.price as string) : undefined;
|
|
26
|
+
const recurring = (price?.recurring as Row | undefined) ?? {};
|
|
27
|
+
const d = p.duration && typeof p.duration === 'object' ? (p.duration as Row) : undefined;
|
|
28
|
+
const startDate = cursor;
|
|
29
|
+
const end = p.end_date !== undefined && p.end_date !== 'now' ? Number(p.end_date)
|
|
30
|
+
: d ? addBillingInterval(startDate, String(d.interval) as Interval, Math.max(1, Number(d.interval_count) || 1))
|
|
31
|
+
: addBillingInterval(startDate, String(recurring.interval ?? 'month') as Interval, Math.max(1, Number(recurring.interval_count) || 1));
|
|
32
|
+
cursor = end;
|
|
33
|
+
return {
|
|
34
|
+
add_invoice_items: [], application_fee_percent: null, automatic_tax: { enabled: false, liability: null, disabled_reason: null }, billing_cycle_anchor: null,
|
|
35
|
+
billing_thresholds: null, collection_method: null, currency: String(price?.currency ?? 'usd'), default_payment_method: null, default_tax_rates: [],
|
|
36
|
+
description: null, discounts: [], end_date: end, invoice_settings: null, items, metadata: p.metadata && typeof p.metadata === 'object' ? p.metadata : {},
|
|
37
|
+
on_behalf_of: null, proration_behavior: typeof p.proration_behavior === 'string' ? p.proration_behavior : 'create_prorations', start_date: startDate,
|
|
38
|
+
transfer_data: null, trial_end: null,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// a schedule starts from a customer or from an existing subscription
|
|
44
|
+
const create: Semantics = async (ctx) => {
|
|
45
|
+
const params = ctx.params;
|
|
46
|
+
const customer = typeof params.customer === 'string' ? params.customer : '';
|
|
47
|
+
const fromSub = typeof params.from_subscription === 'string' ? params.from_subscription : '';
|
|
48
|
+
if (!customer && !fromSub) return fail(ctx, 'Missing required param: customer (or from_subscription).', 400, 'parameter_missing');
|
|
49
|
+
if (customer && !ctx.get('customer', customer)) return fail(ctx, `No such customer: '${customer}'`, 404, 'resource_missing');
|
|
50
|
+
if (fromSub && !ctx.get('subscription', fromSub)) return fail(ctx, `No such subscription: '${fromSub}'`, 404, 'resource_missing');
|
|
51
|
+
// start_date is an instruction ("now" or when), not a field of the schedule
|
|
52
|
+
const start = params.start_date !== undefined && params.start_date !== 'now' ? Number(params.start_date) : Number(ctx.now());
|
|
53
|
+
const phases = phasesOf(ctx, Array.isArray(params.phases) ? (params.phases as Row[]) : [], start);
|
|
54
|
+
const { phases: _p, start_date: _s, default_settings: givenDefaults, ...rest } = params;
|
|
55
|
+
const defaults = givenDefaults && typeof givenDefaults === 'object' ? (givenDefaults as Row) : {};
|
|
56
|
+
const schedId = ctx.mint(SS);
|
|
57
|
+
// a schedule for a customer whose first phase starts now starts its subscription at once, on that phase's items
|
|
58
|
+
// (docs.stripe.com/billing/subscriptions/subscription-schedules#managing)
|
|
59
|
+
let subscription = fromSub || null;
|
|
60
|
+
if (!fromSub && phases.length) {
|
|
61
|
+
const now = Number(ctx.now());
|
|
62
|
+
const subId = ctx.mint('subscription');
|
|
63
|
+
const items = buildSubscriptionItemsList(phases[0]!.items as Row[], subId, now, finder(ctx));
|
|
64
|
+
await created(ctx, 'subscription', { customer, id: subId }, {
|
|
65
|
+
status: 'active', livemode: false, currency: 'usd', collection_method: String((params.default_settings as Row | undefined)?.collection_method ?? 'charge_automatically'),
|
|
66
|
+
cancel_at_period_end: false, start_date: now, billing_cycle_anchor: now, metadata: {}, discounts: [], billing_schedules: [],
|
|
67
|
+
trial_start: null, trial_end: null, current_period_start: now, current_period_end: phases[0]!.end_date, items, schedule: schedId,
|
|
68
|
+
automatic_tax: { enabled: false, liability: null }, billing_mode: { type: 'classic' }, invoice_settings: { issuer: { type: 'self' } },
|
|
69
|
+
});
|
|
70
|
+
await storeItems(ctx, subId, (items.data as Row[]) ?? []);
|
|
71
|
+
subscription = subId;
|
|
72
|
+
}
|
|
73
|
+
return ctx.reply(
|
|
74
|
+
await created(ctx, SS, { ...rest, id: schedId }, {
|
|
75
|
+
status: 'active', livemode: false, phases, current_phase: phases.length ? { start_date: phases[0]!.start_date, end_date: phases[0]!.end_date } : null,
|
|
76
|
+
subscription, released_subscription: null, released_at: null,
|
|
77
|
+
canceled_at: null, completed_at: null, end_behavior: (params.end_behavior as string) ?? 'release',
|
|
78
|
+
renewal_interval: null, metadata: {}, billing_mode: { type: 'classic' },
|
|
79
|
+
// "billing_cycle_anchor: Possible values are phase_start or automatic" and invoice_settings are required (the
|
|
80
|
+
// served spec's default settings); the rest answer what the request set, else null
|
|
81
|
+
default_settings: {
|
|
82
|
+
application_fee_percent: defaults.application_fee_percent ?? null, automatic_tax: { enabled: false, liability: null, disabled_reason: null },
|
|
83
|
+
billing_cycle_anchor: typeof defaults.billing_cycle_anchor === 'string' ? defaults.billing_cycle_anchor : 'automatic', billing_thresholds: null,
|
|
84
|
+
collection_method: typeof defaults.collection_method === 'string' ? defaults.collection_method : 'charge_automatically', default_payment_method: defaults.default_payment_method ?? null,
|
|
85
|
+
description: defaults.description ?? null, invoice_settings: { account_tax_ids: null, days_until_due: null, issuer: { type: 'self' } }, on_behalf_of: null, transfer_data: null,
|
|
86
|
+
},
|
|
87
|
+
// a schedule made from a subscription is its customer's
|
|
88
|
+
customer: customer || String(ctx.get('subscription', fromSub)?.customer ?? ''),
|
|
89
|
+
}),
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
function end(kind: 'cancel' | 'release'): Semantics {
|
|
94
|
+
return async (ctx) => {
|
|
95
|
+
const id = at(ctx, 'schedule');
|
|
96
|
+
const sched = ctx.get(SS, id);
|
|
97
|
+
if (!sched) return scheduleMissing(ctx, id);
|
|
98
|
+
const refused = ctx.legal(SS, 'status', kind === 'cancel' ? 'PostSubscriptionSchedulesScheduleCancel' : 'PostSubscriptionSchedulesScheduleRelease', sched.status, undefined, id);
|
|
99
|
+
if (refused) return ctx.refuse(refused);
|
|
100
|
+
const now = ctx.now();
|
|
101
|
+
const subId = typeof sched.subscription === 'string' ? sched.subscription : undefined;
|
|
102
|
+
const sub = subId ? ctx.get('subscription', subId) : undefined;
|
|
103
|
+
// "Cancels a subscription schedule and its associated subscription immediately (if the subscription schedule has an
|
|
104
|
+
// active subscription)" (docs.stripe.com/api/subscription_schedules/cancel); releasing "will remove its subscription
|
|
105
|
+
// property and set the subscription's ID to the released_subscription property", leaving the subscription in place
|
|
106
|
+
// (docs.stripe.com/api/subscription_schedules/release)
|
|
107
|
+
if (kind === 'cancel' && subId && sub && sub.status !== 'canceled') {
|
|
108
|
+
ctx.legal('subscription', 'status', 'PostSubscriptionSchedulesScheduleCancel', String(sub.status), 'canceled', subId);
|
|
109
|
+
await ctx.write('subscription', subId, { status: 'canceled', canceled_at: now, ended_at: now }, 'subscription.cancel');
|
|
110
|
+
}
|
|
111
|
+
if (kind === 'release' && subId && sub) await ctx.write('subscription', subId, { schedule: null }, 'subscription.update');
|
|
112
|
+
const fields = kind === 'cancel'
|
|
113
|
+
? { status: 'canceled', canceled_at: now, current_phase: null }
|
|
114
|
+
: { status: 'released', released_at: now, released_subscription: subId ?? null, subscription: null, current_phase: null };
|
|
115
|
+
return ctx.reply(await ctx.write(SS, id, fields, `subscription_schedule.${kind}`));
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const retrieve: Semantics = async (ctx) => {
|
|
120
|
+
const s = ctx.get(SS, at(ctx, 'schedule'));
|
|
121
|
+
return s ? ctx.reply(s) : scheduleMissing(ctx, at(ctx, 'schedule'));
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const subscriptionSchedules: Record<string, Semantics> = {
|
|
125
|
+
PostSubscriptionSchedules: create,
|
|
126
|
+
PostSubscriptionSchedulesScheduleCancel: end('cancel'),
|
|
127
|
+
PostSubscriptionSchedulesScheduleRelease: end('release'),
|
|
128
|
+
GetSubscriptionSchedulesSchedule: retrieve,
|
|
129
|
+
};
|