@cosmicdrift/kumiko-bundled-features 0.337.1 → 0.338.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/dist/agent-tools/tool-catalog.js +37 -17
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -0
- package/dist/auth-email-password/handlers/invite-accept.write.js +1 -0
- package/dist/auth-email-password/handlers/invite-info.query.js +1 -0
- package/dist/auth-email-password/handlers/invite-signup-complete.write.js +1 -0
- package/dist/auth-email-password/handlers/signup-confirm.write.js +1 -0
- package/dist/auth-email-password/handlers/signup-request.write.js +1 -1
- package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -0
- package/dist/billing-foundation/aggregate-id.d.ts +2 -0
- package/dist/billing-foundation/aggregate-id.js +8 -0
- package/dist/billing-foundation/checkout-core.d.ts +3 -0
- package/dist/billing-foundation/checkout-core.js +3 -0
- package/dist/billing-foundation/constants.d.ts +31 -0
- package/dist/billing-foundation/constants.js +35 -0
- package/dist/billing-foundation/consumer-protection/confirmation-mail.d.ts +21 -0
- package/dist/billing-foundation/consumer-protection/confirmation-mail.js +125 -0
- package/dist/billing-foundation/consumer-protection/consent-gate.d.ts +32 -0
- package/dist/billing-foundation/consumer-protection/consent-gate.js +88 -0
- package/dist/billing-foundation/consumer-protection/consent-locale.d.ts +5 -0
- package/dist/billing-foundation/consumer-protection/consent-locale.js +17 -0
- package/dist/billing-foundation/consumer-protection/consent-text.d.ts +11 -0
- package/dist/billing-foundation/consumer-protection/consent-text.js +28 -0
- package/dist/billing-foundation/consumer-protection/issue-confirmation.d.ts +15 -0
- package/dist/billing-foundation/consumer-protection/issue-confirmation.js +149 -0
- package/dist/billing-foundation/consumer-protection/register-consent.d.ts +3 -0
- package/dist/billing-foundation/consumer-protection/register-consent.js +63 -0
- package/dist/billing-foundation/consumer-protection/register-termination.d.ts +3 -0
- package/dist/billing-foundation/consumer-protection/register-termination.js +12 -0
- package/dist/billing-foundation/consumer-protection/termination-mail.d.ts +43 -0
- package/dist/billing-foundation/consumer-protection/termination-mail.js +76 -0
- package/dist/billing-foundation/consumer-protection/termination-pages.d.ts +8 -0
- package/dist/billing-foundation/consumer-protection/termination-pages.js +239 -0
- package/dist/billing-foundation/consumer-protection/termination-record.d.ts +51 -0
- package/dist/billing-foundation/consumer-protection/termination-record.js +162 -0
- package/dist/billing-foundation/consumer-protection/termination-request.d.ts +45 -0
- package/dist/billing-foundation/consumer-protection/termination-request.js +263 -0
- package/dist/billing-foundation/consumer-protection/termination-texts.d.ts +62 -0
- package/dist/billing-foundation/consumer-protection/termination-texts.js +168 -0
- package/dist/billing-foundation/events.d.ts +86 -2
- package/dist/billing-foundation/events.js +76 -2
- package/dist/billing-foundation/feature.js +6 -2
- package/dist/billing-foundation/handlers/billing-plans.query.js +19 -1
- package/dist/billing-foundation/handlers/create-checkout-session.write.js +33 -2
- package/dist/billing-foundation/handlers/process-event.write.d.ts +2 -2
- package/dist/billing-foundation/handlers/process-event.write.js +43 -15
- package/dist/billing-foundation/handlers/process-payment-event.write.d.ts +2 -1
- package/dist/billing-foundation/handlers/process-payment-event.write.js +6 -2
- package/dist/billing-foundation/handlers/start-plan-checkout.write.js +15 -1
- package/dist/billing-foundation/handlers/sync-subscription.write.js +0 -1
- package/dist/billing-foundation/i18n.js +58 -0
- package/dist/billing-foundation/index.d.ts +3 -2
- package/dist/billing-foundation/index.js +2 -1
- package/dist/billing-foundation/types.d.ts +49 -9
- package/dist/billing-foundation/validate-options.js +47 -10
- package/dist/billing-foundation/web/billing-plans-panel.js +40 -3
- package/dist/billing-foundation/web/cancel-contract-dialog.d.ts +7 -0
- package/dist/billing-foundation/web/cancel-contract-dialog.js +57 -0
- package/dist/billing-foundation/web/checkout-consent-dialog.d.ts +28 -0
- package/dist/billing-foundation/web/checkout-consent-dialog.js +38 -0
- package/dist/billing-foundation/webhook-handler.js +5 -2
- package/dist/cap-counter/with-cap-enforcement.js +7 -3
- package/dist/cap-overview/access.d.ts +2 -1
- package/dist/cap-overview/access.js +26 -5
- package/dist/cap-overview/feature.d.ts +4 -0
- package/dist/cap-overview/feature.js +8 -6
- package/dist/cap-overview/handlers/caps-usage.query.d.ts +1 -1
- package/dist/cap-overview/handlers/caps-usage.query.js +6 -4
- package/dist/cap-overview/handlers/tenant-caps-list.query.js +12 -7
- package/dist/cap-overview/index.d.ts +2 -2
- package/dist/cap-overview/index.js +2 -2
- package/dist/cap-overview/screens.d.ts +1 -1
- package/dist/cap-overview/screens.js +17 -16
- package/dist/config/handlers/set.write.js +18 -2
- package/dist/crypto-shredding/feature.js +3 -2
- package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +1 -1
- package/dist/crypto-shredding/handlers/forget-subject.write.js +24 -13
- package/dist/custom-fields/feature.js +9 -6
- package/dist/custom-fields/handlers/clear-custom-field.write.js +1 -0
- package/dist/custom-fields/handlers/define-tenant-field.write.js +1 -0
- package/dist/custom-fields/handlers/set-custom-field.write.js +1 -0
- package/dist/delivery/delivery-service.js +9 -7
- package/dist/document-ingest-foundation/feature.js +3 -2
- package/dist/form-draft/handlers/discard.write.js +1 -0
- package/dist/form-draft/handlers/save.write.js +1 -0
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +1 -0
- package/dist/managed-pages/handlers/set.write.js +1 -0
- package/dist/notes-history/executor.d.ts +2 -0
- package/dist/notes-history/executor.js +9 -1
- package/dist/notes-history/feature.d.ts +2 -3
- package/dist/notes-history/feature.js +2 -1
- package/dist/notes-history/handlers/add-note.write.d.ts +2 -1
- package/dist/notes-history/handlers/add-note.write.js +20 -3
- package/dist/notes-history-user-data/hooks.js +26 -8
- package/dist/sessions/handlers/revoke-all-for-user.write.js +1 -0
- package/dist/subscription-mollie/plugin-methods.js +1 -0
- package/dist/subscription-mollie/verify-webhook.js +5 -3
- package/dist/subscription-stripe/plugin-methods.d.ts +3 -1
- package/dist/subscription-stripe/plugin-methods.js +78 -13
- package/dist/subscription-stripe/verify-webhook.js +7 -3
- package/dist/tags/executor.d.ts +2 -0
- package/dist/tags/executor.js +9 -1
- package/dist/tags/feature.d.ts +4 -3
- package/dist/tags/feature.js +4 -2
- package/dist/tags/handlers/assign-tag.write.d.ts +2 -1
- package/dist/tags/handlers/assign-tag.write.js +4 -4
- package/dist/tags/handlers/remove-tag.write.d.ts +2 -1
- package/dist/tags/handlers/remove-tag.write.js +3 -3
- package/dist/tenant-handover/handlers/claim.write.js +1 -0
- package/dist/tenant-lifecycle/handlers/cancel-destruction.write.js +1 -0
- package/dist/tenant-lifecycle/handlers/request-destruction.write.js +1 -0
- package/dist/tier-engine/handlers/get-tenant-tier.query.js +1 -0
- package/dist/tier-engine/handlers/set-tenant-tier.write.js +1 -0
- package/dist/user/handlers/detail.query.js +1 -0
- package/dist/user/handlers/list.query.js +1 -0
- package/dist/user-data-rights/handlers/cancel-deletion.write.js +1 -0
- package/dist/user-data-rights/handlers/download-attempt-list.query.js +1 -0
- package/dist/user-data-rights/handlers/download-by-job.query.js +1 -0
- package/dist/user-data-rights/handlers/download-by-token.query.js +1 -0
- package/dist/user-data-rights/handlers/export-status.query.js +1 -0
- package/dist/user-data-rights/handlers/lift-restriction.write.js +1 -0
- package/dist/user-data-rights/handlers/my-audit-log.query.js +1 -0
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +1 -0
- package/dist/user-data-rights/handlers/request-export.write.js +1 -0
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +1 -0
- package/dist/user-data-rights/run-forget-cleanup.js +30 -15
- package/package.json +9 -9
- package/src/agent-tools/changes.json +14 -0
- package/src/billing-foundation/changes.json +49 -0
- package/src/cap-counter/changes.json +7 -0
- package/src/cap-overview/changes.json +14 -0
- package/src/config/changes.json +7 -0
- package/src/crypto-shredding/changes.json +13 -0
- package/src/custom-fields/changes.json +7 -0
- package/src/delivery/changes.json +7 -0
- package/src/notes-history/changes.json +7 -0
- package/src/subscription-mollie/changes.json +13 -0
- package/src/subscription-stripe/changes.json +13 -0
- package/src/tags/changes.json +7 -0
- package/src/user-data-rights/changes.json +6 -0
|
@@ -36,8 +36,8 @@ const statusEnum = z.enum([
|
|
|
36
36
|
]);
|
|
37
37
|
// Common payload — alle 5 events tragen denselben subscription-state-
|
|
38
38
|
// snapshot. Event-type tagged was passiert ist, payload den state-after.
|
|
39
|
-
//
|
|
40
|
-
//
|
|
39
|
+
// The raw provider event is deliberately not stored: it carries plaintext
|
|
40
|
+
// PII and event headers are not crypto-shreddable.
|
|
41
41
|
export const subscriptionEventPayloadSchema = z.object({
|
|
42
42
|
providerName: z.string().min(1).max(50),
|
|
43
43
|
// 1000, not 200: these two are `tenantOwned: true` on the entity (see
|
|
@@ -54,6 +54,7 @@ export const subscriptionEventPayloadSchema = z.object({
|
|
|
54
54
|
// upcaster. null = the subscription renews; undefined = the provider
|
|
55
55
|
// doesn't report cancelAt at all — projection.ts tells the two apart.
|
|
56
56
|
cancelAtIso: z.string().min(1).nullable().optional(),
|
|
57
|
+
consentId: z.string().min(1).max(100).optional(),
|
|
57
58
|
});
|
|
58
59
|
// =============================================================================
|
|
59
60
|
// payment-received — one-off-payments (checkout mode "payment")
|
|
@@ -74,4 +75,77 @@ export const paymentEventPayloadSchema = z.object({
|
|
|
74
75
|
// subscriptionEventPayloadSchema's same rationale.
|
|
75
76
|
providerCustomerId: z.string().min(1).max(1000),
|
|
76
77
|
priceId: z.string().min(1).max(200),
|
|
78
|
+
consentId: z.string().min(1).max(100).optional(),
|
|
79
|
+
});
|
|
80
|
+
// =============================================================================
|
|
81
|
+
// checkout-consent-recorded — consumer-protection consent
|
|
82
|
+
// =============================================================================
|
|
83
|
+
//
|
|
84
|
+
// Appended onto the subscription- or payment-stream (by checkout mode) after
|
|
85
|
+
// the provider handed out the checkout URL. No projection applies it. Carries
|
|
86
|
+
// no email or IP: the consenting user is identified by `actorUserId` only.
|
|
87
|
+
export const CHECKOUT_CONSENT_RECORDED_EVENT_SHORT = "checkout-consent-recorded";
|
|
88
|
+
export const CHECKOUT_CONSENT_RECORDED_EVENT_QN = `${BILLING_FOUNDATION_FEATURE}:event:${CHECKOUT_CONSENT_RECORDED_EVENT_SHORT}`;
|
|
89
|
+
export const checkoutConsentRecordedPayloadSchema = z.object({
|
|
90
|
+
consentId: z.string().min(1).max(100),
|
|
91
|
+
mode: z.enum(["subscription", "payment"]),
|
|
92
|
+
tier: z.string().min(1).max(50).nullable(),
|
|
93
|
+
priceId: z.string().min(1).max(200),
|
|
94
|
+
unitAmount: z.number().nullable(),
|
|
95
|
+
currency: z.string().nullable(),
|
|
96
|
+
interval: z.string().nullable(),
|
|
97
|
+
intervalCount: z.number().nullable(),
|
|
98
|
+
consentTextVersion: z.string().min(1).max(64),
|
|
99
|
+
termsHash: z.string().length(64),
|
|
100
|
+
termsTemplateVersion: z.number(),
|
|
101
|
+
locale: z.string().min(2).max(35),
|
|
102
|
+
actorUserId: z.string().min(1),
|
|
103
|
+
});
|
|
104
|
+
// =============================================================================
|
|
105
|
+
// contract-confirmation-issued — § 312f confirmation mail sent
|
|
106
|
+
// =============================================================================
|
|
107
|
+
//
|
|
108
|
+
// Appended onto the stream that carries the consent, BEFORE the mail is
|
|
109
|
+
// handed to delivery: the append is the optimistic-concurrency guard that
|
|
110
|
+
// keeps a concurrent or replayed run from sending a second mail.
|
|
111
|
+
export const CONTRACT_CONFIRMATION_ISSUED_EVENT_SHORT = "contract-confirmation-issued";
|
|
112
|
+
export const CONTRACT_CONFIRMATION_ISSUED_EVENT_QN = `${BILLING_FOUNDATION_FEATURE}:event:${CONTRACT_CONFIRMATION_ISSUED_EVENT_SHORT}`;
|
|
113
|
+
export const contractConfirmationIssuedPayloadSchema = z.object({
|
|
114
|
+
consentId: z.string().min(1).max(100),
|
|
115
|
+
issuedAtIso: z.string().min(1),
|
|
116
|
+
locale: z.string().min(2).max(35),
|
|
117
|
+
termsTemplateVersion: z.number(),
|
|
118
|
+
});
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// contract-termination-requested / -unmatched — § 312k cancellation
|
|
121
|
+
// =============================================================================
|
|
122
|
+
//
|
|
123
|
+
// Payloads carry no name, email or reason: those only travel in the mails.
|
|
124
|
+
// `requested` goes onto the tenant's subscription stream; `unmatched` onto a
|
|
125
|
+
// system-tenant stream of its own, keyed by the request id.
|
|
126
|
+
export const CONTRACT_TERMINATION_DECLARATION_TYPES = ["termination", "withdrawal"];
|
|
127
|
+
export const CONTRACT_TERMINATION_KINDS = ["ordinary", "extraordinary"];
|
|
128
|
+
export const CONTRACT_TERMINATION_CHANNELS = ["public", "account"];
|
|
129
|
+
export const PROVIDER_CANCEL_OUTCOMES = ["period-end", "immediately", "none"];
|
|
130
|
+
export const CONTRACT_TERMINATION_REQUESTED_EVENT_SHORT = "contract-termination-requested";
|
|
131
|
+
export const CONTRACT_TERMINATION_REQUESTED_EVENT_QN = `${BILLING_FOUNDATION_FEATURE}:event:${CONTRACT_TERMINATION_REQUESTED_EVENT_SHORT}`;
|
|
132
|
+
export const contractTerminationRequestedPayloadSchema = z.object({
|
|
133
|
+
requestId: z.string().min(1).max(100),
|
|
134
|
+
declarationType: z.enum(CONTRACT_TERMINATION_DECLARATION_TYPES),
|
|
135
|
+
terminationKind: z.enum(CONTRACT_TERMINATION_KINDS),
|
|
136
|
+
channel: z.enum(CONTRACT_TERMINATION_CHANNELS),
|
|
137
|
+
receivedAtIso: z.string().min(1),
|
|
138
|
+
effectiveAtIso: z.string().min(1).nullable(),
|
|
139
|
+
providerCancel: z.enum(PROVIDER_CANCEL_OUTCOMES),
|
|
140
|
+
});
|
|
141
|
+
export const CONTRACT_TERMINATION_UNMATCHED_AGGREGATE_TYPE = "contract-termination-unmatched";
|
|
142
|
+
export const CONTRACT_TERMINATION_UNMATCHED_EVENT_SHORT = "contract-termination-unmatched";
|
|
143
|
+
export const CONTRACT_TERMINATION_UNMATCHED_EVENT_QN = `${BILLING_FOUNDATION_FEATURE}:event:${CONTRACT_TERMINATION_UNMATCHED_EVENT_SHORT}`;
|
|
144
|
+
export const contractTerminationUnmatchedPayloadSchema = z.object({
|
|
145
|
+
requestId: z.string().min(1).max(100),
|
|
146
|
+
declarationType: z.enum(CONTRACT_TERMINATION_DECLARATION_TYPES),
|
|
147
|
+
terminationKind: z.enum(CONTRACT_TERMINATION_KINDS),
|
|
148
|
+
channel: z.literal("public"),
|
|
149
|
+
receivedAtIso: z.string().min(1),
|
|
150
|
+
matchResult: z.enum(["none", "ambiguous"]),
|
|
77
151
|
});
|
|
@@ -55,13 +55,14 @@ import { defineFeature, EXT_TENANT_DATA, } from "@cosmicdrift/kumiko-framework/e
|
|
|
55
55
|
// resolves against, see event-store.ts's own import comment (#1438).
|
|
56
56
|
import { Temporal as TemporalPolyfill } from "temporal-polyfill";
|
|
57
57
|
import { BILLING_FOUNDATION_FEATURE, SUBSCRIPTION_PROVIDER_EXTENSION, SubscriptionFoundationHandlers, } from "./constants.js";
|
|
58
|
+
import { registerConsumerProtection } from "./consumer-protection/register-consent.js";
|
|
58
59
|
import { paymentEntity, subscriptionEntity } from "./entities.js";
|
|
59
60
|
import { INVOICE_PAID_EVENT_QN, INVOICE_PAID_EVENT_SHORT, INVOICE_PAYMENT_FAILED_EVENT_QN, INVOICE_PAYMENT_FAILED_EVENT_SHORT, PAYMENT_AGGREGATE_TYPE, PAYMENT_RECEIVED_EVENT_QN, PAYMENT_RECEIVED_EVENT_SHORT, paymentEventPayloadSchema, SUBSCRIPTION_AGGREGATE_TYPE, SUBSCRIPTION_CANCELED_EVENT_QN, SUBSCRIPTION_CANCELED_EVENT_SHORT, SUBSCRIPTION_CREATED_EVENT_QN, SUBSCRIPTION_CREATED_EVENT_SHORT, SUBSCRIPTION_UPDATED_EVENT_QN, SUBSCRIPTION_UPDATED_EVENT_SHORT, subscriptionEventPayloadSchema, } from "./events.js";
|
|
60
61
|
import { createBillingPlansQuery } from "./handlers/billing-plans.query.js";
|
|
61
62
|
import { createCheckoutSessionHandler } from "./handlers/create-checkout-session.write.js";
|
|
62
63
|
import { createPortalSessionHandler } from "./handlers/create-portal-session.write.js";
|
|
63
64
|
import { listSubscriptionsQuery } from "./handlers/list-subscriptions.query.js";
|
|
64
|
-
import {
|
|
65
|
+
import { createProcessEventHandler } from "./handlers/process-event.write.js";
|
|
65
66
|
import { processPaymentEventHandler } from "./handlers/process-payment-event.write.js";
|
|
66
67
|
import { createStartPlanCheckoutHandler } from "./handlers/start-plan-checkout.write.js";
|
|
67
68
|
import { createSwitchPlanHandler } from "./handlers/switch-plan.write.js";
|
|
@@ -163,7 +164,7 @@ export function createBillingFoundationFeature(options = {}) {
|
|
|
163
164
|
// - create-checkout-session: bare priceId-driven checkout (hardened,
|
|
164
165
|
// see checkout-core)
|
|
165
166
|
// - create-portal-session: Tenant-Admin "Manage Subscription"-flow
|
|
166
|
-
r.writeHandler(
|
|
167
|
+
r.writeHandler(createProcessEventHandler(widened.now));
|
|
167
168
|
r.writeHandler(createCheckoutSessionHandler(widened));
|
|
168
169
|
r.writeHandler(createPortalSessionHandler(widened));
|
|
169
170
|
// - process-payment-event: programmatic entry-point from the webhook-
|
|
@@ -182,6 +183,9 @@ export function createBillingFoundationFeature(options = {}) {
|
|
|
182
183
|
// fire from create-checkout-session even without a catalog — register
|
|
183
184
|
// unconditionally rather than splitting the i18n surface by option.
|
|
184
185
|
r.translations({ keys: BILLING_FOUNDATION_I18N });
|
|
186
|
+
if (widened.consumerProtection) {
|
|
187
|
+
registerConsumerProtection(r, widened, widened.consumerProtection);
|
|
188
|
+
}
|
|
185
189
|
if (widened.catalog) {
|
|
186
190
|
const { catalog } = widened;
|
|
187
191
|
r.queryHandler(createBillingPlansQuery(widened, catalog));
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// when `createBillingFoundationFeature` gets a `catalog`.
|
|
4
4
|
import * as z from "zod";
|
|
5
5
|
import { findCatalogProvider } from "../checkout-core.js";
|
|
6
|
+
import { CONSENT_TEXTS, consentTextVersion, } from "../consumer-protection/consent-text.js";
|
|
6
7
|
import { buildBillingPlans } from "../plan-catalog.js";
|
|
7
8
|
const billingPlansSchema = z.object({}).strict();
|
|
8
9
|
export function createBillingPlansQuery(options, catalog) {
|
|
@@ -13,7 +14,24 @@ export function createBillingPlansQuery(options, catalog) {
|
|
|
13
14
|
access: { roles: catalog.viewRoles },
|
|
14
15
|
handler: async (_query, ctx) => {
|
|
15
16
|
const found = findCatalogProvider(ctx, catalog);
|
|
16
|
-
|
|
17
|
+
const result = await buildBillingPlans(ctx, found?.plugin ?? null, catalog, options.now);
|
|
18
|
+
const { consumerProtection } = options;
|
|
19
|
+
if (!consumerProtection)
|
|
20
|
+
return result;
|
|
21
|
+
return {
|
|
22
|
+
...result,
|
|
23
|
+
consumerProtection: {
|
|
24
|
+
consentTexts: {
|
|
25
|
+
de: consentTextView("de"),
|
|
26
|
+
en: consentTextView("en"),
|
|
27
|
+
},
|
|
28
|
+
legalLinks: consumerProtection.legalLinks,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
17
31
|
},
|
|
18
32
|
};
|
|
19
33
|
}
|
|
34
|
+
function consentTextView(locale) {
|
|
35
|
+
const { earlyPerformance, withdrawalLoss } = CONSENT_TEXTS[locale];
|
|
36
|
+
return { earlyPerformance, withdrawalLoss, consentTextVersion: consentTextVersion(locale) };
|
|
37
|
+
}
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
// prefer start-plan-checkout/switch-plan over calling this handler with a
|
|
23
23
|
// hand-picked priceId.
|
|
24
24
|
import * as z from "zod";
|
|
25
|
-
import { openCheckout } from "../checkout-core.js";
|
|
25
|
+
import { findProviderPlugin, openCheckout } from "../checkout-core.js";
|
|
26
|
+
import { consentCheckoutFields, consentPayloadSchema, prepareConsent, recordConsent, } from "../consumer-protection/consent-gate.js";
|
|
26
27
|
const createCheckoutSessionSchema = z.object({
|
|
27
28
|
/** Welcher Provider — entityName eines registrierten subscription-
|
|
28
29
|
* Plugins ("stripe" / "paypal" / ...). */
|
|
@@ -41,16 +42,24 @@ const createCheckoutSessionSchema = z.object({
|
|
|
41
42
|
mode: z.enum(["subscription", "payment"]).optional(),
|
|
42
43
|
});
|
|
43
44
|
export function createCheckoutSessionHandler(options) {
|
|
45
|
+
const consumerProtection = options.consumerProtection;
|
|
46
|
+
const schema = consumerProtection
|
|
47
|
+
? createCheckoutSessionSchema.extend({ consent: consentPayloadSchema })
|
|
48
|
+
: createCheckoutSessionSchema;
|
|
44
49
|
return {
|
|
45
50
|
name: "create-checkout-session",
|
|
46
51
|
description: 'Opens a hosted checkout page at the named subscription provider for the caller\'s tenant and returns its URL; use it when a tenant admin wants to make a one-off payment (mode: "payment") or subscribe to a price already known to be valid. Redirect URLs must share the configured baseUrl origin. Prefer billing-foundation:write:start-plan-checkout / :switch-plan for catalog-driven plan purchases.',
|
|
47
|
-
schema
|
|
52
|
+
schema,
|
|
48
53
|
// Tenant-Admin-only — the tenant must deliberately configure its own
|
|
49
54
|
// subscription. SystemAdmin as a fallback for operator-initiated flows.
|
|
50
55
|
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
51
56
|
handler: async (event, ctx) => {
|
|
52
57
|
// @cast-boundary engine-payload — dispatcher-zod-validated payload
|
|
53
58
|
const payload = event.payload;
|
|
59
|
+
const mode = payload.mode ?? "subscription";
|
|
60
|
+
const consent = consumerProtection && payload.consent
|
|
61
|
+
? await prepareConsent(ctx, consumerProtection, payload.consent, mode)
|
|
62
|
+
: undefined;
|
|
54
63
|
const result = await openCheckout(ctx, { baseUrl: options.baseUrl, catalog: options.catalog, now: options.now }, {
|
|
55
64
|
providerName: payload.providerName,
|
|
56
65
|
priceId: payload.priceId,
|
|
@@ -58,7 +67,16 @@ export function createCheckoutSessionHandler(options) {
|
|
|
58
67
|
cancelUrl: payload.cancelUrl,
|
|
59
68
|
...(payload.providerCustomerId && { providerCustomerId: payload.providerCustomerId }),
|
|
60
69
|
...(payload.mode && { mode: payload.mode }),
|
|
70
|
+
...(consent && consentCheckoutFields(consent)),
|
|
61
71
|
});
|
|
72
|
+
if (consent) {
|
|
73
|
+
const plugin = findProviderPlugin(ctx, payload.providerName)?.plugin;
|
|
74
|
+
await recordConsent(ctx, consent, {
|
|
75
|
+
tier: mode === "subscription" ? (plugin?.priceToTier?.[payload.priceId] ?? null) : null,
|
|
76
|
+
priceId: payload.priceId,
|
|
77
|
+
price: await lookupPrice(ctx, plugin, payload.priceId),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
62
80
|
return {
|
|
63
81
|
isSuccess: true,
|
|
64
82
|
data: { url: result.url, providerName: result.providerName },
|
|
@@ -66,3 +84,16 @@ export function createCheckoutSessionHandler(options) {
|
|
|
66
84
|
},
|
|
67
85
|
};
|
|
68
86
|
}
|
|
87
|
+
// A failed price lookup must not lose a consent the buyer already gave at the
|
|
88
|
+
// provider, so it degrades to null price fields.
|
|
89
|
+
async function lookupPrice(ctx, plugin, priceId) {
|
|
90
|
+
if (!plugin?.retrievePrices)
|
|
91
|
+
return null;
|
|
92
|
+
try {
|
|
93
|
+
const prices = await plugin.retrievePrices(ctx, [priceId]);
|
|
94
|
+
return prices.find((p) => p.priceId === priceId) ?? null;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -22,11 +22,11 @@ export declare const processEventSchema: z.ZodObject<{
|
|
|
22
22
|
tier: z.ZodString;
|
|
23
23
|
currentPeriodEndIso: z.ZodString;
|
|
24
24
|
cancelAtIso: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
25
|
-
|
|
25
|
+
consentId: z.ZodOptional<z.ZodString>;
|
|
26
26
|
}, z.core.$strip>;
|
|
27
27
|
export type ProcessEventPayload = z.infer<typeof processEventSchema>;
|
|
28
28
|
export declare function appendSubscriptionEvent(ctx: HandlerContext, tenantId: string, payload: ProcessEventPayload): Promise<{
|
|
29
29
|
readonly duplicate: boolean;
|
|
30
30
|
readonly subscriptionAggregateId: string;
|
|
31
31
|
}>;
|
|
32
|
-
export declare
|
|
32
|
+
export declare function createProcessEventHandler(now: () => Temporal.Instant): WriteHandlerDef;
|
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
import { configuredPiiSubjectKms, encryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
15
15
|
import * as z from "zod";
|
|
16
16
|
import { subscriptionAggregateId } from "../aggregate-id.js";
|
|
17
|
-
import { SubscriptionEventTypes, SubscriptionStatuses } from "../constants.js";
|
|
17
|
+
import { isSubscriptionBlockingCheckout, SubscriptionEventTypes, SubscriptionStatuses, } from "../constants.js";
|
|
18
18
|
import { SUBSCRIPTION_PII_FIELDS, subscriptionEntity } from "../entities.js";
|
|
19
19
|
import { INVOICE_PAID_EVENT_QN, INVOICE_PAYMENT_FAILED_EVENT_QN, SUBSCRIPTION_AGGREGATE_TYPE, SUBSCRIPTION_CANCELED_EVENT_QN, SUBSCRIPTION_CREATED_EVENT_QN, SUBSCRIPTION_UPDATED_EVENT_QN, } from "../events.js";
|
|
20
|
+
import { getSubscriptionForTenant } from "../get-subscription-for-tenant.js";
|
|
20
21
|
// =============================================================================
|
|
21
22
|
// Input-Schema = der normalisierte SubscriptionEvent (ohne tenantId, der
|
|
22
23
|
// kommt aus event.user.tenantId — der webhook-handler setzt den
|
|
@@ -46,7 +47,7 @@ export const processEventSchema = z.object({
|
|
|
46
47
|
tier: z.string().min(1).max(50),
|
|
47
48
|
currentPeriodEndIso: z.string().min(1),
|
|
48
49
|
cancelAtIso: z.string().min(1).nullable().optional(),
|
|
49
|
-
|
|
50
|
+
consentId: z.string().min(1).max(100).optional(),
|
|
50
51
|
});
|
|
51
52
|
// Map normalized SubscriptionEventType → fully-qualified ES event-name.
|
|
52
53
|
const NORMALIZED_TO_ES_EVENT = {
|
|
@@ -129,11 +130,11 @@ export async function appendSubscriptionEvent(ctx, tenantId, payload) {
|
|
|
129
130
|
tier: payload.tier,
|
|
130
131
|
currentPeriodEndIso: payload.currentPeriodEndIso,
|
|
131
132
|
...(payload.cancelAtIso !== undefined && { cancelAtIso: payload.cancelAtIso }),
|
|
133
|
+
...(payload.consentId !== undefined && { consentId: payload.consentId }),
|
|
132
134
|
};
|
|
133
135
|
const headers = {
|
|
134
136
|
providerEventId: payload.providerEventId,
|
|
135
137
|
providerName: payload.providerName,
|
|
136
|
-
rawPayload: payload.rawPayload,
|
|
137
138
|
};
|
|
138
139
|
await ctx.unsafeAppendEvent({
|
|
139
140
|
aggregateId: aggId,
|
|
@@ -151,15 +152,42 @@ export async function appendSubscriptionEvent(ctx, tenantId, payload) {
|
|
|
151
152
|
// SystemAdmin-only: dieser handler wird ausschließlich vom programmatic
|
|
152
153
|
// webhook-handler aufgerufen (mit einem internal SystemUser), nie vom
|
|
153
154
|
// Tenant-Admin direkt.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
155
|
+
// One subscription aggregate exists per tenant, but a tenant can legitimately hold two provider
|
|
156
|
+
// subscriptions over time (a stale `incomplete` one superseded by a fresh checkout). A late or
|
|
157
|
+
// retried event of the old subscription must not overwrite the row of the live one, so only a
|
|
158
|
+
// `created` event may replace a blocking row that belongs to a different provider subscription.
|
|
159
|
+
function isStaleSubscriptionEvent(current, payload, now) {
|
|
160
|
+
if (current === null)
|
|
161
|
+
return false;
|
|
162
|
+
if (payload.type === SubscriptionEventTypes.created)
|
|
163
|
+
return false;
|
|
164
|
+
const sameSubscription = current.providerName === payload.providerName &&
|
|
165
|
+
current.providerSubscriptionId === payload.providerSubscriptionId;
|
|
166
|
+
return !sameSubscription && isSubscriptionBlockingCheckout(current, now);
|
|
167
|
+
}
|
|
168
|
+
export function createProcessEventHandler(now) {
|
|
169
|
+
return {
|
|
170
|
+
name: "process-event",
|
|
171
|
+
agent: { expose: false },
|
|
172
|
+
schema: processEventSchema,
|
|
173
|
+
access: { roles: ["SystemAdmin"] },
|
|
174
|
+
handler: async (event, ctx) => {
|
|
175
|
+
// @cast-boundary engine-payload — dispatcher-zod-validated payload
|
|
176
|
+
const payload = event.payload;
|
|
177
|
+
const current = await getSubscriptionForTenant(ctx, event.user.tenantId);
|
|
178
|
+
if (isStaleSubscriptionEvent(current, payload, now())) {
|
|
179
|
+
ctx.log?.warn(`[billing-foundation:process-event] dropped stale ${payload.type} ${payload.providerEventId}: tenant already tracks another subscription`);
|
|
180
|
+
return {
|
|
181
|
+
isSuccess: true,
|
|
182
|
+
data: {
|
|
183
|
+
duplicate: false,
|
|
184
|
+
stale: true,
|
|
185
|
+
subscriptionAggregateId: subscriptionAggregateId(event.user.tenantId),
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
const result = await appendSubscriptionEvent(ctx, event.user.tenantId, payload);
|
|
190
|
+
return { isSuccess: true, data: result };
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
@@ -3,8 +3,9 @@ import * as z from "zod";
|
|
|
3
3
|
export declare const processPaymentEventSchema: z.ZodObject<{
|
|
4
4
|
providerEventId: z.ZodString;
|
|
5
5
|
providerName: z.ZodString;
|
|
6
|
+
providerCheckoutId: z.ZodOptional<z.ZodString>;
|
|
6
7
|
providerCustomerId: z.ZodString;
|
|
7
8
|
priceId: z.ZodString;
|
|
8
|
-
|
|
9
|
+
consentId: z.ZodOptional<z.ZodString>;
|
|
9
10
|
}, z.core.$strip>;
|
|
10
11
|
export declare const processPaymentEventHandler: WriteHandlerDef;
|
|
@@ -17,9 +17,10 @@ import { PAYMENT_AGGREGATE_TYPE, PAYMENT_RECEIVED_EVENT_QN, } from "../events.js
|
|
|
17
17
|
export const processPaymentEventSchema = z.object({
|
|
18
18
|
providerEventId: z.string().min(1).max(200),
|
|
19
19
|
providerName: z.string().min(1).max(50),
|
|
20
|
+
providerCheckoutId: z.string().min(1).max(200).optional(),
|
|
20
21
|
providerCustomerId: z.string().min(1).max(200),
|
|
21
22
|
priceId: z.string().min(1).max(200),
|
|
22
|
-
|
|
23
|
+
consentId: z.string().min(1).max(100).optional(),
|
|
23
24
|
});
|
|
24
25
|
// SystemAdmin-only: this handler is called exclusively by the programmatic
|
|
25
26
|
// webhook-handler (with an internal SystemUser), never directly by the
|
|
@@ -71,11 +72,14 @@ export const processPaymentEventHandler = {
|
|
|
71
72
|
providerName: payload.providerName,
|
|
72
73
|
providerCustomerId: encryptedFields["providerCustomerId"],
|
|
73
74
|
priceId: payload.priceId,
|
|
75
|
+
...(payload.consentId !== undefined && { consentId: payload.consentId }),
|
|
74
76
|
};
|
|
75
77
|
const headers = {
|
|
76
78
|
providerEventId: payload.providerEventId,
|
|
77
79
|
providerName: payload.providerName,
|
|
78
|
-
|
|
80
|
+
...(payload.providerCheckoutId !== undefined && {
|
|
81
|
+
providerCheckoutId: payload.providerCheckoutId,
|
|
82
|
+
}),
|
|
79
83
|
};
|
|
80
84
|
await ctx.unsafeAppendEvent({
|
|
81
85
|
aggregateId: aggId,
|
|
@@ -5,13 +5,16 @@
|
|
|
5
5
|
import { UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
|
|
6
6
|
import * as z from "zod";
|
|
7
7
|
import { assertBillingEnabled, assertNoActiveSubscription, isNonEmptyStringArray, joinBaseUrl, openCheckout, resolveCatalogProvider, } from "../checkout-core.js";
|
|
8
|
+
import { consentCheckoutFields, consentPayloadSchema, prepareConsent, recordConsent, } from "../consumer-protection/consent-gate.js";
|
|
8
9
|
import { purchaseRolesOf, resolvePlanPrices } from "../plan-catalog.js";
|
|
9
10
|
export function createStartPlanCheckoutHandler(options, catalog) {
|
|
10
11
|
const plans = catalog.plans;
|
|
11
12
|
if (!isNonEmptyStringArray(plans)) {
|
|
12
13
|
throw new Error("start-plan-checkout: catalog.plans must not be empty");
|
|
13
14
|
}
|
|
14
|
-
const
|
|
15
|
+
const consumerProtection = options.consumerProtection;
|
|
16
|
+
const tierSchema = z.object({ tier: z.enum(plans) });
|
|
17
|
+
const schema = (consumerProtection ? tierSchema.extend({ consent: consentPayloadSchema }) : tierSchema).strict();
|
|
15
18
|
return {
|
|
16
19
|
name: "start-plan-checkout",
|
|
17
20
|
description: "Starts a hosted checkout for a plan tier when the tenant has no active subscription; the server picks price and redirect URLs.",
|
|
@@ -31,6 +34,9 @@ export function createStartPlanCheckoutHandler(options, catalog) {
|
|
|
31
34
|
message: `subscription-foundation: no live price resolved for tier "${payload.tier}"`,
|
|
32
35
|
});
|
|
33
36
|
}
|
|
37
|
+
const consent = consumerProtection && payload.consent
|
|
38
|
+
? await prepareConsent(ctx, consumerProtection, payload.consent, "subscription")
|
|
39
|
+
: undefined;
|
|
34
40
|
const baseUrl = options.baseUrl ?? "";
|
|
35
41
|
const result = await openCheckout(ctx, { baseUrl: options.baseUrl, catalog, now: options.now }, {
|
|
36
42
|
providerName,
|
|
@@ -38,9 +44,17 @@ export function createStartPlanCheckoutHandler(options, catalog) {
|
|
|
38
44
|
successUrl: joinBaseUrl(baseUrl, catalog.successPath),
|
|
39
45
|
cancelUrl: joinBaseUrl(baseUrl, catalog.cancelPath),
|
|
40
46
|
mode: "subscription",
|
|
47
|
+
...(consent && consentCheckoutFields(consent)),
|
|
41
48
|
...(existing?.providerName === providerName &&
|
|
42
49
|
existing.providerCustomerId && { providerCustomerId: existing.providerCustomerId }),
|
|
43
50
|
});
|
|
51
|
+
if (consent) {
|
|
52
|
+
await recordConsent(ctx, consent, {
|
|
53
|
+
tier: payload.tier,
|
|
54
|
+
priceId: resolved.priceId,
|
|
55
|
+
price: resolved.price,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
44
58
|
return { isSuccess: true, data: { url: result.url } };
|
|
45
59
|
},
|
|
46
60
|
};
|
|
@@ -35,6 +35,58 @@ export const BILLING_FOUNDATION_I18N = {
|
|
|
35
35
|
"billing-foundation.plans.subscriptionPending": {
|
|
36
36
|
en: "Your plan change is being processed.",
|
|
37
37
|
},
|
|
38
|
+
"billing-foundation.consent.title": { en: "Review your order" },
|
|
39
|
+
"billing-foundation.consent.cancelAnytime": {
|
|
40
|
+
en: "You can cancel at any time, effective at the end of the current period.",
|
|
41
|
+
},
|
|
42
|
+
"billing-foundation.consent.renews.day": { en: "Renews every day until cancelled." },
|
|
43
|
+
"billing-foundation.consent.renews.week": { en: "Renews every week until cancelled." },
|
|
44
|
+
"billing-foundation.consent.renews.month": { en: "Renews every month until cancelled." },
|
|
45
|
+
"billing-foundation.consent.renews.year": { en: "Renews every year until cancelled." },
|
|
46
|
+
"billing-foundation.consent.renewsEvery.day": {
|
|
47
|
+
en: "Renews every {count} days until cancelled.",
|
|
48
|
+
},
|
|
49
|
+
"billing-foundation.consent.renewsEvery.week": {
|
|
50
|
+
en: "Renews every {count} weeks until cancelled.",
|
|
51
|
+
},
|
|
52
|
+
"billing-foundation.consent.renewsEvery.month": {
|
|
53
|
+
en: "Renews every {count} months until cancelled.",
|
|
54
|
+
},
|
|
55
|
+
"billing-foundation.consent.renewsEvery.year": {
|
|
56
|
+
en: "Renews every {count} years until cancelled.",
|
|
57
|
+
},
|
|
58
|
+
"billing-foundation.consent.link.terms": { en: "Terms" },
|
|
59
|
+
"billing-foundation.consent.link.withdrawal": { en: "Withdrawal policy" },
|
|
60
|
+
"billing-foundation.consent.link.privacy": { en: "Privacy policy" },
|
|
61
|
+
"billing-foundation.consent.order": { en: "Order with obligation to pay" },
|
|
62
|
+
"billing-foundation.consent.back": { en: "Back" },
|
|
63
|
+
"billing-foundation.cancel.open": { en: "Cancel contract here" },
|
|
64
|
+
"billing-foundation.cancel.title": { en: "Cancel contract" },
|
|
65
|
+
"billing-foundation.cancel.declaration": { en: "Declaration" },
|
|
66
|
+
"billing-foundation.cancel.declaration.termination": { en: "Termination" },
|
|
67
|
+
"billing-foundation.cancel.declaration.withdrawal": { en: "Withdrawal" },
|
|
68
|
+
"billing-foundation.cancel.withdrawalHint": {
|
|
69
|
+
en: "A withdrawal is only possible within the statutory withdrawal period.",
|
|
70
|
+
},
|
|
71
|
+
"billing-foundation.cancel.kind": { en: "Type of termination" },
|
|
72
|
+
"billing-foundation.cancel.kind.ordinary": { en: "Ordinary" },
|
|
73
|
+
"billing-foundation.cancel.kind.extraordinary": { en: "Extraordinary (for cause)" },
|
|
74
|
+
"billing-foundation.cancel.reason": { en: "Reason" },
|
|
75
|
+
"billing-foundation.cancel.continue": { en: "Continue" },
|
|
76
|
+
"billing-foundation.cancel.back": { en: "Back" },
|
|
77
|
+
"billing-foundation.cancel.close": { en: "Close" },
|
|
78
|
+
"billing-foundation.cancel.confirmQuestion": {
|
|
79
|
+
en: "Do you want to submit this declaration now? Declaration: {declaration}, type: {kind}.",
|
|
80
|
+
},
|
|
81
|
+
"billing-foundation.cancel.submit": { en: "Cancel now" },
|
|
82
|
+
"billing-foundation.cancel.receivedAt": { en: "We received your declaration on {date}." },
|
|
83
|
+
"billing-foundation.cancel.effectiveAt": { en: "It takes effect on {date}." },
|
|
84
|
+
"billing-foundation.cancel.effectiveUnknown": {
|
|
85
|
+
en: "We will confirm the effective date by email.",
|
|
86
|
+
},
|
|
87
|
+
"billing-foundation.cancel.emailConfirmation": {
|
|
88
|
+
en: "You will receive a confirmation by email.",
|
|
89
|
+
},
|
|
38
90
|
"billing-foundation.errors.redirectOriginNotAllowed": {
|
|
39
91
|
en: "This redirect URL is not allowed for this app.",
|
|
40
92
|
},
|
|
@@ -67,4 +119,10 @@ export const BILLING_FOUNDATION_I18N = {
|
|
|
67
119
|
"billing-foundation.errors.priceUnavailable": {
|
|
68
120
|
en: "This plan's price is temporarily unavailable.",
|
|
69
121
|
},
|
|
122
|
+
"billing-foundation.errors.consentTextOutdated": {
|
|
123
|
+
en: "The consent text has changed. Reload the page and confirm again.",
|
|
124
|
+
},
|
|
125
|
+
"billing-foundation.errors.termsUnavailable": {
|
|
126
|
+
en: "The terms are temporarily unavailable. Please try again later.",
|
|
127
|
+
},
|
|
70
128
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { paymentAggregateId, subscriptionAggregateId } from "./aggregate-id.js";
|
|
2
2
|
export { type BillingInfo, type BillingInfoQueryDeps, createBillingInfoQueryConfig, } from "./billing-info-query.js";
|
|
3
3
|
export { isBillingEnabled, type ResolvedProvider, resolveProviderPlugin, } from "./checkout-core.js";
|
|
4
|
-
export { BILLING_FOUNDATION_FEATURE, BILLING_PLANS_PANEL_COMPONENT, BILLING_PLANS_SCREEN_ID, type BillingEventKind, BillingEventKinds, type BillingPlanAction, BillingPlanActions, DEFAULT_PURCHASE_ROLES, isSwitchableSubscriptionStatus, isTerminalSubscriptionStatus, SUBSCRIPTION_PROVIDER_EXTENSION, type SubscriptionEventType, SubscriptionEventTypes, SubscriptionFoundationHandlers, SubscriptionFoundationQueries, type SubscriptionStatus, SubscriptionStatuses, } from "./constants.js";
|
|
4
|
+
export { BILLING_FOUNDATION_FEATURE, BILLING_PLANS_PANEL_COMPONENT, BILLING_PLANS_SCREEN_ID, type BillingEventKind, BillingEventKinds, type BillingPlanAction, BillingPlanActions, DEFAULT_PURCHASE_ROLES, isSwitchableSubscriptionStatus, isTerminalSubscriptionStatus, parseProviderConsentId, SUBSCRIPTION_PROVIDER_EXTENSION, type SubscriptionCancelTiming, SubscriptionCancelTimings, type SubscriptionEventType, SubscriptionEventTypes, SubscriptionFoundationHandlers, SubscriptionFoundationQueries, type SubscriptionStatus, SubscriptionStatuses, } from "./constants.js";
|
|
5
|
+
export { type ContractTerminationRoutesOptions, createContractTerminationRoutes, } from "./consumer-protection/termination-pages.js";
|
|
5
6
|
export { paymentEntity, subscriptionEntity } from "./entities.js";
|
|
6
7
|
export { INVOICE_PAID_EVENT_QN, INVOICE_PAID_EVENT_SHORT, INVOICE_PAYMENT_FAILED_EVENT_QN, INVOICE_PAYMENT_FAILED_EVENT_SHORT, PAYMENT_AGGREGATE_TYPE, PAYMENT_RECEIVED_EVENT_QN, PAYMENT_RECEIVED_EVENT_SHORT, type PaymentEventHeaders, type PaymentEventPayload, paymentEventPayloadSchema, SUBSCRIPTION_AGGREGATE_TYPE, SUBSCRIPTION_CANCELED_EVENT_QN, SUBSCRIPTION_CANCELED_EVENT_SHORT, SUBSCRIPTION_CREATED_EVENT_QN, SUBSCRIPTION_CREATED_EVENT_SHORT, SUBSCRIPTION_UPDATED_EVENT_QN, SUBSCRIPTION_UPDATED_EVENT_SHORT, type SubscriptionEventHeaders, type SubscriptionEventPayload, subscriptionEventPayloadSchema, } from "./events.js";
|
|
7
8
|
export { billingFoundationFeature, createBillingFoundationFeature } from "./feature.js";
|
|
@@ -9,5 +10,5 @@ export { getSubscriptionForTenant, type SubscriptionView } from "./get-subscript
|
|
|
9
10
|
export { paymentsProjectionTable, subscriptionsProjectionTable } from "./projection.js";
|
|
10
11
|
export { billingPlansPanel, createBillingPlansScreen } from "./screens.js";
|
|
11
12
|
export { createSubscriptionTierSync, effectiveTierFromSubscription, SUBSCRIPTION_WEBHOOK_PATH, type SubscriptionTierSyncDeps, } from "./subscription-tier-sync.js";
|
|
12
|
-
export { type BillingFoundationOptions, type BillingPlanBenefit, type BillingPlanCatalog, type BillingPlanPrice, type BillingPlansResult, type BillingPlanView, KNOWN_RECURRING_INTERVALS, type PaymentEvent, type ProviderPrice, type ProviderSubscriptionSnapshot, type RecurringInterval, type SubscriptionEvent, type SubscriptionProviderPlugin, } from "./types.js";
|
|
13
|
+
export { type BillingFoundationOptions, type BillingPlanBenefit, type BillingPlanCatalog, type BillingPlanPrice, type BillingPlansResult, type BillingPlanView, type ConsumerProtectionOptions, KNOWN_RECURRING_INTERVALS, type PaymentEvent, type ProviderPrice, type ProviderSubscriptionSnapshot, type RecurringInterval, type SubscriptionEvent, type SubscriptionProviderPlugin, } from "./types.js";
|
|
13
14
|
export { createSubscriptionWebhookRoute, type SubscriptionWebhookRouteOptions, } from "./webhook-handler.js";
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
export { paymentAggregateId, subscriptionAggregateId } from "./aggregate-id.js";
|
|
3
3
|
export { createBillingInfoQueryConfig, } from "./billing-info-query.js";
|
|
4
4
|
export { isBillingEnabled, resolveProviderPlugin, } from "./checkout-core.js";
|
|
5
|
-
export { BILLING_FOUNDATION_FEATURE, BILLING_PLANS_PANEL_COMPONENT, BILLING_PLANS_SCREEN_ID, BillingEventKinds, BillingPlanActions, DEFAULT_PURCHASE_ROLES, isSwitchableSubscriptionStatus, isTerminalSubscriptionStatus, SUBSCRIPTION_PROVIDER_EXTENSION, SubscriptionEventTypes, SubscriptionFoundationHandlers, SubscriptionFoundationQueries, SubscriptionStatuses, } from "./constants.js";
|
|
5
|
+
export { BILLING_FOUNDATION_FEATURE, BILLING_PLANS_PANEL_COMPONENT, BILLING_PLANS_SCREEN_ID, BillingEventKinds, BillingPlanActions, DEFAULT_PURCHASE_ROLES, isSwitchableSubscriptionStatus, isTerminalSubscriptionStatus, parseProviderConsentId, SUBSCRIPTION_PROVIDER_EXTENSION, SubscriptionCancelTimings, SubscriptionEventTypes, SubscriptionFoundationHandlers, SubscriptionFoundationQueries, SubscriptionStatuses, } from "./constants.js";
|
|
6
|
+
export { createContractTerminationRoutes, } from "./consumer-protection/termination-pages.js";
|
|
6
7
|
export { paymentEntity, subscriptionEntity } from "./entities.js";
|
|
7
8
|
export { INVOICE_PAID_EVENT_QN, INVOICE_PAID_EVENT_SHORT, INVOICE_PAYMENT_FAILED_EVENT_QN, INVOICE_PAYMENT_FAILED_EVENT_SHORT, PAYMENT_AGGREGATE_TYPE, PAYMENT_RECEIVED_EVENT_QN, PAYMENT_RECEIVED_EVENT_SHORT, paymentEventPayloadSchema, SUBSCRIPTION_AGGREGATE_TYPE, SUBSCRIPTION_CANCELED_EVENT_QN, SUBSCRIPTION_CANCELED_EVENT_SHORT, SUBSCRIPTION_CREATED_EVENT_QN, SUBSCRIPTION_CREATED_EVENT_SHORT, SUBSCRIPTION_UPDATED_EVENT_QN, SUBSCRIPTION_UPDATED_EVENT_SHORT, subscriptionEventPayloadSchema, } from "./events.js";
|
|
8
9
|
export { billingFoundationFeature, createBillingFoundationFeature } from "./feature.js";
|