@noodleseed/one 0.52.1 → 0.54.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/node_modules/@noodle-borg/service/dist/billing/active-commercial-entitlement.d.ts +25 -0
- package/node_modules/@noodle-borg/service/dist/billing/active-commercial-entitlement.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/active-commercial-entitlement.js +94 -0
- package/node_modules/@noodle-borg/service/dist/billing/active-commercial-entitlement.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/commercial-entitlements.d.ts +8 -0
- package/node_modules/@noodle-borg/service/dist/billing/commercial-entitlements.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/commercial-entitlements.js +49 -0
- package/node_modules/@noodle-borg/service/dist/billing/commercial-entitlements.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.js +3 -2
- package/node_modules/@noodle-borg/service/dist/billing/in-memory.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/integration.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/integration.js +0 -3
- package/node_modules/@noodle-borg/service/dist/billing/integration.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/model.d.ts +16 -3
- package/node_modules/@noodle-borg/service/dist/billing/model.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/model.js +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/model.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/paid-plan-catalog.d.ts +26 -0
- package/node_modules/@noodle-borg/service/dist/billing/paid-plan-catalog.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/paid-plan-catalog.js +94 -0
- package/node_modules/@noodle-borg/service/dist/billing/paid-plan-catalog.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-authoritative-authority.d.ts +4 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-authoritative-authority.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-authoritative-authority.js +21 -7
- package/node_modules/@noodle-borg/service/dist/billing/postgres-authoritative-authority.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-counters.js +4 -5
- package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-counters.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-projection.d.ts +0 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-projection.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-projection.js +92 -27
- package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-projection.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission.d.ts +0 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission.js +72 -27
- package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-production-app-admission.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-production-app-admission.js +56 -26
- package/node_modules/@noodle-borg/service/dist/billing/postgres-production-app-admission.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-records.d.ts +4 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-records.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-records.js +38 -9
- package/node_modules/@noodle-borg/service/dist/billing/postgres-records.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js +28 -21
- package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-authority.d.ts +5 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-authority.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-authority.js +97 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-authority.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-persistence.d.ts +50 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-persistence.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-persistence.js +221 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-persistence.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-support.d.ts +8 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-support.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-support.js +42 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation-support.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation.d.ts +15 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation.js +123 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-reconciliation.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-schema.d.ts +4 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-schema.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-schema.js +419 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-schema.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/subscription-model.d.ts +40 -0
- package/node_modules/@noodle-borg/service/dist/billing/subscription-model.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/subscription-model.js +388 -0
- package/node_modules/@noodle-borg/service/dist/billing/subscription-model.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/subscription-reconciliation.d.ts +45 -0
- package/node_modules/@noodle-borg/service/dist/billing/subscription-reconciliation.d.ts.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/subscription-reconciliation.js +165 -0
- package/node_modules/@noodle-borg/service/dist/billing/subscription-reconciliation.js.map +1 -0
- package/node_modules/@noodle-borg/service/dist/billing-public.d.ts +6 -1
- package/node_modules/@noodle-borg/service/dist/billing-public.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing-public.js +5 -0
- package/node_modules/@noodle-borg/service/dist/billing-public.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { parseBillingCommercialV2Entitlements } from './commercial-entitlements.js';
|
|
2
|
+
import { billingContentChecksum, validateBillingAccountId, } from './model.js';
|
|
3
|
+
import { getBillingPaidPlanBaseAmountMinor, getBillingPublicPlanVersion, } from './paid-plan-catalog.js';
|
|
4
|
+
const BILLING_PAYMENT_GRACE_DURATION_MS = 7 * 24 * 60 * 60 * 1_000;
|
|
5
|
+
export function createBillingBaseSubscriptionRevision(input) {
|
|
6
|
+
const content = normalizeSubscriptionRevisionContent(input);
|
|
7
|
+
return Object.freeze({
|
|
8
|
+
...content,
|
|
9
|
+
contentChecksum: billingContentChecksum(content),
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export function parseBillingBaseSubscriptionRevision(value) {
|
|
13
|
+
const input = requireRecord('subscription revision', value);
|
|
14
|
+
if (input.schemaVersion !== 1)
|
|
15
|
+
throw new Error('subscription revision schema is invalid');
|
|
16
|
+
const content = normalizeSubscriptionRevisionContent({
|
|
17
|
+
subscriptionId: requireString(input, 'subscriptionId'),
|
|
18
|
+
billingAccountId: requireString(input, 'billingAccountId'),
|
|
19
|
+
version: requireNumber(input, 'version'),
|
|
20
|
+
planVersionId: requireString(input, 'planVersionId'),
|
|
21
|
+
state: requireString(input, 'state'),
|
|
22
|
+
billingInterval: requireString(input, 'billingInterval'),
|
|
23
|
+
currency: requireString(input, 'currency'),
|
|
24
|
+
baseAmountMinor: requireNumber(input, 'baseAmountMinor'),
|
|
25
|
+
currentPeriodStart: requireString(input, 'currentPeriodStart'),
|
|
26
|
+
currentPeriodEnd: requireString(input, 'currentPeriodEnd'),
|
|
27
|
+
effectiveFrom: requireString(input, 'effectiveFrom'),
|
|
28
|
+
effectiveUntil: requireString(input, 'effectiveUntil'),
|
|
29
|
+
renews: requireBoolean(input, 'renews'),
|
|
30
|
+
verifiedAt: requireString(input, 'verifiedAt'),
|
|
31
|
+
createdAt: requireString(input, 'createdAt'),
|
|
32
|
+
});
|
|
33
|
+
const checksum = requireString(input, 'contentChecksum');
|
|
34
|
+
if (billingContentChecksum(content) !== checksum) {
|
|
35
|
+
throw new Error('subscription revision failed checksum verification');
|
|
36
|
+
}
|
|
37
|
+
return Object.freeze({ ...content, contentChecksum: checksum });
|
|
38
|
+
}
|
|
39
|
+
export function createPaidEntitlementSnapshot(input) {
|
|
40
|
+
const sourceSubscription = parseBillingBaseSubscriptionRevision(input.sourceSubscription);
|
|
41
|
+
const previousSnapshot = validatePreviousEntitlementSnapshot(input.previousSnapshot);
|
|
42
|
+
if (previousSnapshot.billingAccountId !== sourceSubscription.billingAccountId) {
|
|
43
|
+
throw new Error('paid entitlement snapshot must preserve its billing account');
|
|
44
|
+
}
|
|
45
|
+
if (input.version !== previousSnapshot.version + 1) {
|
|
46
|
+
throw new Error('paid entitlement snapshot version must follow the previous snapshot');
|
|
47
|
+
}
|
|
48
|
+
const plan = getCanonicalPaidPlan(sourceSubscription.planVersionId);
|
|
49
|
+
const commercial = parseBillingCommercialV2Entitlements(plan.entitlements);
|
|
50
|
+
if (commercial.planCode === 'free' || commercial.planCode !== plan.planCode) {
|
|
51
|
+
throw new Error('paid entitlement snapshot requires a canonical paid plan');
|
|
52
|
+
}
|
|
53
|
+
const content = normalizePaidSnapshotContent({
|
|
54
|
+
id: input.id,
|
|
55
|
+
schemaVersion: 2,
|
|
56
|
+
billingAccountId: sourceSubscription.billingAccountId,
|
|
57
|
+
version: input.version,
|
|
58
|
+
planVersionId: plan.id,
|
|
59
|
+
planCode: plan.planCode,
|
|
60
|
+
planVersion: plan.version,
|
|
61
|
+
sourceKind: 'subscription',
|
|
62
|
+
generationReason: 'subscription-reconciled',
|
|
63
|
+
verificationStatus: 'verified',
|
|
64
|
+
sourceSubscriptionId: sourceSubscription.subscriptionId,
|
|
65
|
+
sourceSubscriptionVersion: sourceSubscription.version,
|
|
66
|
+
effectiveFrom: sourceSubscription.effectiveFrom,
|
|
67
|
+
effectiveUntil: sourceSubscription.effectiveUntil,
|
|
68
|
+
monthlyUsageAnchor: previousSnapshot.monthlyUsageAnchor,
|
|
69
|
+
entitlements: plan.entitlements,
|
|
70
|
+
verifiedAt: sourceSubscription.verifiedAt,
|
|
71
|
+
createdAt: sourceSubscription.createdAt,
|
|
72
|
+
});
|
|
73
|
+
return Object.freeze({
|
|
74
|
+
...content,
|
|
75
|
+
contentChecksum: paidSnapshotChecksum(content),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function validatePreviousEntitlementSnapshot(snapshot) {
|
|
79
|
+
if (snapshot.schemaVersion === 2)
|
|
80
|
+
return parsePaidEntitlementSnapshot(snapshot);
|
|
81
|
+
if (snapshot.schemaVersion !== 1 ||
|
|
82
|
+
snapshot.sourceKind !== 'system-free' ||
|
|
83
|
+
snapshot.generationReason !== 'default-account-created' ||
|
|
84
|
+
snapshot.verificationStatus !== 'verified') {
|
|
85
|
+
throw new Error('previous entitlement snapshot provenance is invalid');
|
|
86
|
+
}
|
|
87
|
+
const plan = getBillingPublicPlanVersion(snapshot.planVersionId);
|
|
88
|
+
if (plan === undefined ||
|
|
89
|
+
plan.planCode !== 'free' ||
|
|
90
|
+
snapshot.planCode !== plan.planCode ||
|
|
91
|
+
snapshot.planVersion !== plan.version ||
|
|
92
|
+
billingContentChecksum(snapshot.entitlements) !== billingContentChecksum(plan.entitlements)) {
|
|
93
|
+
throw new Error('previous entitlement snapshot does not match the canonical Free plan');
|
|
94
|
+
}
|
|
95
|
+
const contentChecksum = billingContentChecksum({
|
|
96
|
+
billingAccountId: snapshot.billingAccountId,
|
|
97
|
+
version: snapshot.version,
|
|
98
|
+
planVersionId: snapshot.planVersionId,
|
|
99
|
+
effectiveFrom: snapshot.effectiveFrom,
|
|
100
|
+
monthlyUsageAnchor: snapshot.monthlyUsageAnchor,
|
|
101
|
+
entitlements: snapshot.entitlements,
|
|
102
|
+
});
|
|
103
|
+
if (contentChecksum !== snapshot.contentChecksum) {
|
|
104
|
+
throw new Error('previous entitlement snapshot failed checksum verification');
|
|
105
|
+
}
|
|
106
|
+
validateEntitlementSnapshotId(snapshot.id);
|
|
107
|
+
validateBillingAccountId(snapshot.billingAccountId);
|
|
108
|
+
positiveInteger('previous entitlement snapshot version', snapshot.version);
|
|
109
|
+
const effectiveFrom = canonicalInstant('previous entitlement start', snapshot.effectiveFrom);
|
|
110
|
+
const monthlyUsageAnchor = canonicalInstant('previous monthly usage anchor', snapshot.monthlyUsageAnchor);
|
|
111
|
+
const verifiedAt = canonicalInstant('previous entitlement verified at', snapshot.verifiedAt);
|
|
112
|
+
const createdAt = canonicalInstant('previous entitlement created at', snapshot.createdAt);
|
|
113
|
+
if (monthlyUsageAnchor > effectiveFrom || verifiedAt < effectiveFrom || createdAt < verifiedAt) {
|
|
114
|
+
throw new Error('previous entitlement snapshot timing is invalid');
|
|
115
|
+
}
|
|
116
|
+
return snapshot;
|
|
117
|
+
}
|
|
118
|
+
export function parsePaidEntitlementSnapshot(value) {
|
|
119
|
+
const input = requireRecord('paid entitlement snapshot', value);
|
|
120
|
+
const content = normalizePaidSnapshotContent({
|
|
121
|
+
id: requireString(input, 'id'),
|
|
122
|
+
schemaVersion: requireNumber(input, 'schemaVersion'),
|
|
123
|
+
billingAccountId: requireString(input, 'billingAccountId'),
|
|
124
|
+
version: requireNumber(input, 'version'),
|
|
125
|
+
planVersionId: requireString(input, 'planVersionId'),
|
|
126
|
+
planCode: requireString(input, 'planCode'),
|
|
127
|
+
planVersion: requireNumber(input, 'planVersion'),
|
|
128
|
+
sourceKind: requireString(input, 'sourceKind'),
|
|
129
|
+
generationReason: requireString(input, 'generationReason'),
|
|
130
|
+
verificationStatus: requireString(input, 'verificationStatus'),
|
|
131
|
+
sourceSubscriptionId: requireString(input, 'sourceSubscriptionId'),
|
|
132
|
+
sourceSubscriptionVersion: requireNumber(input, 'sourceSubscriptionVersion'),
|
|
133
|
+
effectiveFrom: requireString(input, 'effectiveFrom'),
|
|
134
|
+
effectiveUntil: requireString(input, 'effectiveUntil'),
|
|
135
|
+
monthlyUsageAnchor: requireString(input, 'monthlyUsageAnchor'),
|
|
136
|
+
entitlements: requireEntitlements(input.entitlements),
|
|
137
|
+
verifiedAt: requireString(input, 'verifiedAt'),
|
|
138
|
+
createdAt: requireString(input, 'createdAt'),
|
|
139
|
+
});
|
|
140
|
+
const checksum = requireString(input, 'contentChecksum');
|
|
141
|
+
if (paidSnapshotChecksum(content) !== checksum) {
|
|
142
|
+
throw new Error('paid entitlement snapshot failed checksum verification');
|
|
143
|
+
}
|
|
144
|
+
const plan = getCanonicalPaidPlan(content.planVersionId);
|
|
145
|
+
if (content.planCode !== plan.planCode ||
|
|
146
|
+
content.planVersion !== plan.version ||
|
|
147
|
+
billingContentChecksum(content.entitlements) !== billingContentChecksum(plan.entitlements)) {
|
|
148
|
+
throw new Error('paid entitlement snapshot does not match the canonical paid plan');
|
|
149
|
+
}
|
|
150
|
+
return Object.freeze({ ...content, contentChecksum: checksum });
|
|
151
|
+
}
|
|
152
|
+
function getCanonicalPaidPlan(planVersionId) {
|
|
153
|
+
const plan = getBillingPublicPlanVersion(planVersionId);
|
|
154
|
+
if (plan === undefined || plan.planCode === 'free') {
|
|
155
|
+
throw new Error('paid entitlement snapshot requires a canonical paid plan');
|
|
156
|
+
}
|
|
157
|
+
const contentChecksum = billingContentChecksum({
|
|
158
|
+
id: plan.id,
|
|
159
|
+
planCode: plan.planCode,
|
|
160
|
+
version: plan.version,
|
|
161
|
+
effectiveFrom: plan.effectiveFrom,
|
|
162
|
+
entitlements: plan.entitlements,
|
|
163
|
+
});
|
|
164
|
+
if (contentChecksum !== plan.contentChecksum) {
|
|
165
|
+
throw new Error('canonical paid plan failed checksum verification');
|
|
166
|
+
}
|
|
167
|
+
return plan;
|
|
168
|
+
}
|
|
169
|
+
function normalizeSubscriptionRevisionContent(input) {
|
|
170
|
+
const state = input.state;
|
|
171
|
+
if (state !== 'active' && state !== 'payment_grace' && state !== 'ended') {
|
|
172
|
+
throw new Error('subscription state is invalid');
|
|
173
|
+
}
|
|
174
|
+
if (input.billingInterval !== 'month' && input.billingInterval !== 'year') {
|
|
175
|
+
throw new Error('billing interval is invalid');
|
|
176
|
+
}
|
|
177
|
+
if (input.currency !== 'usd')
|
|
178
|
+
throw new Error('subscription currency is invalid');
|
|
179
|
+
if (input.planVersionId !== 'pro@1' && input.planVersionId !== 'scale@1') {
|
|
180
|
+
throw new Error('subscription revision requires a paid public plan');
|
|
181
|
+
}
|
|
182
|
+
if (!Number.isSafeInteger(input.baseAmountMinor) || input.baseAmountMinor < 0) {
|
|
183
|
+
throw new Error('base amount minor must be a non-negative safe integer');
|
|
184
|
+
}
|
|
185
|
+
if (input.baseAmountMinor !==
|
|
186
|
+
getBillingPaidPlanBaseAmountMinor(input.planVersionId, input.billingInterval)) {
|
|
187
|
+
throw new Error('subscription base amount does not match the public plan');
|
|
188
|
+
}
|
|
189
|
+
if (state === 'ended' && input.renews)
|
|
190
|
+
throw new Error('ended subscriptions cannot renew');
|
|
191
|
+
const currentPeriodStart = canonicalInstant('subscription period start', input.currentPeriodStart);
|
|
192
|
+
const currentPeriodEnd = canonicalInstant('subscription period end', input.currentPeriodEnd);
|
|
193
|
+
if (currentPeriodEnd <= currentPeriodStart) {
|
|
194
|
+
throw new Error('subscription period end must be after its start');
|
|
195
|
+
}
|
|
196
|
+
const effectiveFrom = canonicalInstant('subscription effective start', input.effectiveFrom);
|
|
197
|
+
const effectiveUntil = canonicalInstant('subscription effective end', input.effectiveUntil);
|
|
198
|
+
if (effectiveUntil <= effectiveFrom) {
|
|
199
|
+
throw new Error('subscription effective end must be after its start');
|
|
200
|
+
}
|
|
201
|
+
const verifiedAt = canonicalInstant('subscription verified at', input.verifiedAt);
|
|
202
|
+
const createdAt = canonicalInstant('subscription created at', input.createdAt);
|
|
203
|
+
if (verifiedAt < effectiveFrom) {
|
|
204
|
+
throw new Error('subscription cannot be verified before access starts');
|
|
205
|
+
}
|
|
206
|
+
if (createdAt < verifiedAt) {
|
|
207
|
+
throw new Error('subscription record cannot predate verification');
|
|
208
|
+
}
|
|
209
|
+
if (state === 'active' && effectiveUntil !== currentPeriodEnd) {
|
|
210
|
+
throw new Error('active subscription access must end with its current paid period');
|
|
211
|
+
}
|
|
212
|
+
if (state === 'active' &&
|
|
213
|
+
(effectiveFrom < currentPeriodStart || effectiveFrom >= currentPeriodEnd)) {
|
|
214
|
+
throw new Error('active subscription access must fall within its current paid period');
|
|
215
|
+
}
|
|
216
|
+
if (state === 'payment_grace') {
|
|
217
|
+
const expectedGraceEnd = new Date(new Date(currentPeriodEnd).getTime() + BILLING_PAYMENT_GRACE_DURATION_MS).toISOString();
|
|
218
|
+
if (effectiveUntil !== expectedGraceEnd) {
|
|
219
|
+
throw new Error('payment grace must extend the paid period by exactly seven days');
|
|
220
|
+
}
|
|
221
|
+
if (verifiedAt < currentPeriodEnd) {
|
|
222
|
+
throw new Error('payment grace cannot be verified before the paid period ends');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (state === 'ended' && verifiedAt < effectiveUntil) {
|
|
226
|
+
throw new Error('ended subscription cannot be verified before access ends');
|
|
227
|
+
}
|
|
228
|
+
return Object.freeze({
|
|
229
|
+
schemaVersion: 1,
|
|
230
|
+
subscriptionId: validateBillingSubscriptionId(input.subscriptionId),
|
|
231
|
+
billingAccountId: validateBillingAccountId(input.billingAccountId),
|
|
232
|
+
version: positiveInteger('subscription revision version', input.version),
|
|
233
|
+
planVersionId: scalar('plan version id', input.planVersionId),
|
|
234
|
+
state,
|
|
235
|
+
billingInterval: input.billingInterval,
|
|
236
|
+
currency: input.currency,
|
|
237
|
+
baseAmountMinor: input.baseAmountMinor,
|
|
238
|
+
currentPeriodStart,
|
|
239
|
+
currentPeriodEnd,
|
|
240
|
+
effectiveFrom,
|
|
241
|
+
effectiveUntil,
|
|
242
|
+
renews: input.renews,
|
|
243
|
+
verifiedAt,
|
|
244
|
+
createdAt,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function normalizePaidSnapshotContent(input) {
|
|
248
|
+
if (input.schemaVersion !== 2 ||
|
|
249
|
+
input.sourceKind !== 'subscription' ||
|
|
250
|
+
input.generationReason !== 'subscription-reconciled' ||
|
|
251
|
+
input.verificationStatus !== 'verified') {
|
|
252
|
+
throw new Error('paid entitlement snapshot provenance is invalid');
|
|
253
|
+
}
|
|
254
|
+
const commercial = parseBillingCommercialV2Entitlements(input.entitlements);
|
|
255
|
+
if (commercial.planCode === 'free' || commercial.planCode !== input.planCode) {
|
|
256
|
+
throw new Error('paid entitlement snapshot plan is invalid');
|
|
257
|
+
}
|
|
258
|
+
if (input.planVersion !== 1 || input.planVersionId !== `${commercial.planCode}@1`) {
|
|
259
|
+
throw new Error('paid entitlement snapshot plan version is invalid');
|
|
260
|
+
}
|
|
261
|
+
const effectiveFrom = canonicalInstant('paid entitlement start', input.effectiveFrom);
|
|
262
|
+
const effectiveUntil = canonicalInstant('paid entitlement end', input.effectiveUntil);
|
|
263
|
+
if (effectiveUntil <= effectiveFrom) {
|
|
264
|
+
throw new Error('paid entitlement end must be after its start');
|
|
265
|
+
}
|
|
266
|
+
const monthlyUsageAnchor = canonicalInstant('monthly usage anchor', input.monthlyUsageAnchor);
|
|
267
|
+
const verifiedAt = canonicalInstant('paid entitlement verified at', input.verifiedAt);
|
|
268
|
+
const createdAt = canonicalInstant('paid entitlement created at', input.createdAt);
|
|
269
|
+
if (monthlyUsageAnchor > effectiveFrom) {
|
|
270
|
+
throw new Error('monthly usage anchor cannot start after paid access');
|
|
271
|
+
}
|
|
272
|
+
if (verifiedAt < effectiveFrom) {
|
|
273
|
+
throw new Error('paid entitlement cannot be verified before access starts');
|
|
274
|
+
}
|
|
275
|
+
if (createdAt < verifiedAt) {
|
|
276
|
+
throw new Error('paid entitlement record cannot predate verification');
|
|
277
|
+
}
|
|
278
|
+
return Object.freeze({
|
|
279
|
+
id: validateEntitlementSnapshotId(input.id),
|
|
280
|
+
schemaVersion: 2,
|
|
281
|
+
billingAccountId: validateBillingAccountId(input.billingAccountId),
|
|
282
|
+
version: positiveInteger('entitlement snapshot version', input.version),
|
|
283
|
+
planVersionId: scalar('plan version id', input.planVersionId),
|
|
284
|
+
planCode: commercial.planCode,
|
|
285
|
+
planVersion: positiveInteger('plan version', input.planVersion),
|
|
286
|
+
sourceKind: 'subscription',
|
|
287
|
+
generationReason: 'subscription-reconciled',
|
|
288
|
+
verificationStatus: 'verified',
|
|
289
|
+
sourceSubscriptionId: validateBillingSubscriptionId(input.sourceSubscriptionId),
|
|
290
|
+
sourceSubscriptionVersion: positiveInteger('source subscription version', input.sourceSubscriptionVersion),
|
|
291
|
+
effectiveFrom,
|
|
292
|
+
effectiveUntil,
|
|
293
|
+
monthlyUsageAnchor,
|
|
294
|
+
entitlements: Object.freeze({ ...input.entitlements }),
|
|
295
|
+
verifiedAt,
|
|
296
|
+
createdAt,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
function paidSnapshotChecksum(snapshot) {
|
|
300
|
+
return billingContentChecksum({
|
|
301
|
+
schemaVersion: snapshot.schemaVersion,
|
|
302
|
+
billingAccountId: snapshot.billingAccountId,
|
|
303
|
+
version: snapshot.version,
|
|
304
|
+
planVersionId: snapshot.planVersionId,
|
|
305
|
+
sourceKind: snapshot.sourceKind,
|
|
306
|
+
generationReason: snapshot.generationReason,
|
|
307
|
+
sourceSubscriptionId: snapshot.sourceSubscriptionId,
|
|
308
|
+
sourceSubscriptionVersion: snapshot.sourceSubscriptionVersion,
|
|
309
|
+
effectiveFrom: snapshot.effectiveFrom,
|
|
310
|
+
effectiveUntil: snapshot.effectiveUntil,
|
|
311
|
+
monthlyUsageAnchor: snapshot.monthlyUsageAnchor,
|
|
312
|
+
entitlements: snapshot.entitlements,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
export function validateBillingSubscriptionId(value) {
|
|
316
|
+
if (!/^bs_[0-9a-f-]{36}$/.test(value))
|
|
317
|
+
throw new Error('invalid billing subscription id');
|
|
318
|
+
return value;
|
|
319
|
+
}
|
|
320
|
+
function validateEntitlementSnapshotId(value) {
|
|
321
|
+
if (!/^es_[0-9a-f-]{36}$/.test(value))
|
|
322
|
+
throw new Error('invalid entitlement snapshot id');
|
|
323
|
+
return value;
|
|
324
|
+
}
|
|
325
|
+
function positiveInteger(name, value) {
|
|
326
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
327
|
+
throw new Error(`${name} must be positive`);
|
|
328
|
+
return value;
|
|
329
|
+
}
|
|
330
|
+
function canonicalInstant(name, value) {
|
|
331
|
+
const date = new Date(value);
|
|
332
|
+
if (!Number.isFinite(date.getTime()) || date.toISOString() !== value) {
|
|
333
|
+
throw new Error(`${name} must be a canonical ISO-8601 instant`);
|
|
334
|
+
}
|
|
335
|
+
return value;
|
|
336
|
+
}
|
|
337
|
+
function scalar(name, value) {
|
|
338
|
+
const normalized = value.trim();
|
|
339
|
+
if (normalized.length === 0 ||
|
|
340
|
+
normalized.length > 512 ||
|
|
341
|
+
normalized !== value ||
|
|
342
|
+
[...normalized].some((character) => {
|
|
343
|
+
const code = character.charCodeAt(0);
|
|
344
|
+
return code <= 0x1f || code === 0x7f;
|
|
345
|
+
})) {
|
|
346
|
+
throw new Error(`${name} must be a non-empty scalar identifier`);
|
|
347
|
+
}
|
|
348
|
+
return normalized;
|
|
349
|
+
}
|
|
350
|
+
function requireRecord(name, value) {
|
|
351
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
352
|
+
throw new Error(`${name} must be an object`);
|
|
353
|
+
}
|
|
354
|
+
return value;
|
|
355
|
+
}
|
|
356
|
+
function requireString(record, key) {
|
|
357
|
+
const value = record[key];
|
|
358
|
+
if (typeof value !== 'string')
|
|
359
|
+
throw new Error(`${key} must be a string`);
|
|
360
|
+
return value;
|
|
361
|
+
}
|
|
362
|
+
function requireNumber(record, key) {
|
|
363
|
+
const value = record[key];
|
|
364
|
+
if (typeof value !== 'number')
|
|
365
|
+
throw new Error(`${key} must be a number`);
|
|
366
|
+
return value;
|
|
367
|
+
}
|
|
368
|
+
function requireBoolean(record, key) {
|
|
369
|
+
const value = record[key];
|
|
370
|
+
if (typeof value !== 'boolean')
|
|
371
|
+
throw new Error(`${key} must be a boolean`);
|
|
372
|
+
return value;
|
|
373
|
+
}
|
|
374
|
+
function requireEntitlements(value) {
|
|
375
|
+
const record = requireRecord('paid entitlements', value);
|
|
376
|
+
const entitlements = {};
|
|
377
|
+
for (const [key, candidate] of Object.entries(record)) {
|
|
378
|
+
if (candidate !== null &&
|
|
379
|
+
typeof candidate !== 'boolean' &&
|
|
380
|
+
typeof candidate !== 'string' &&
|
|
381
|
+
(typeof candidate !== 'number' || !Number.isFinite(candidate))) {
|
|
382
|
+
throw new Error(`paid entitlement ${key} is invalid`);
|
|
383
|
+
}
|
|
384
|
+
entitlements[key] = candidate;
|
|
385
|
+
}
|
|
386
|
+
return Object.freeze(entitlements);
|
|
387
|
+
}
|
|
388
|
+
//# sourceMappingURL=subscription-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-model.js","sourceRoot":"","sources":["../../src/billing/subscription-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { AuditEventInput } from '@noodle-borg/module';
|
|
2
|
+
import { type BillingBaseSubscriptionRevisionInput, type BillingBaseSubscriptionRevisionRecord } from './subscription-model.js';
|
|
3
|
+
export declare const BILLING_PAID_ADMISSION_CONTRACT_VERSION: 2;
|
|
4
|
+
export interface BillingCurrentBaseSubscriptionExpectation {
|
|
5
|
+
readonly subscriptionId: string;
|
|
6
|
+
readonly revisionVersion: number;
|
|
7
|
+
}
|
|
8
|
+
export interface BillingSubscriptionReconciliationRequest {
|
|
9
|
+
readonly schemaVersion: 1;
|
|
10
|
+
readonly billingAccountId: string;
|
|
11
|
+
readonly idempotencyKey: string;
|
|
12
|
+
readonly expectedActiveSnapshotVersion: number;
|
|
13
|
+
readonly expectedCurrentBaseSubscription: BillingCurrentBaseSubscriptionExpectation | null;
|
|
14
|
+
readonly snapshotId: string;
|
|
15
|
+
readonly revision: BillingBaseSubscriptionRevisionInput;
|
|
16
|
+
}
|
|
17
|
+
export interface NormalizedBillingSubscriptionReconciliationRequest extends Omit<BillingSubscriptionReconciliationRequest, 'revision'> {
|
|
18
|
+
readonly revision: BillingBaseSubscriptionRevisionRecord;
|
|
19
|
+
}
|
|
20
|
+
export interface BillingSubscriptionReconciliationResult {
|
|
21
|
+
readonly schemaVersion: 1;
|
|
22
|
+
readonly billingAccountId: string;
|
|
23
|
+
readonly subscriptionId: string;
|
|
24
|
+
readonly subscriptionRevisionVersion: number;
|
|
25
|
+
readonly snapshotId: string;
|
|
26
|
+
readonly snapshotVersion: number;
|
|
27
|
+
readonly planVersionId: string;
|
|
28
|
+
readonly reconciledAt: string;
|
|
29
|
+
readonly replayed: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface BillingSubscriptionReconciliationStore {
|
|
32
|
+
reconcilePaidSubscription(request: BillingSubscriptionReconciliationRequest): Promise<BillingSubscriptionReconciliationResult>;
|
|
33
|
+
}
|
|
34
|
+
export type BillingSubscriptionReconciliationConflictCode = 'idempotency_key_conflict' | 'paid_admission_contract_unavailable' | 'billing_account_conflict' | 'billing_account_not_enforced' | 'billing_account_enforcement_unavailable' | 'paid_subscription_contract_invalid' | 'idempotency_evidence_invalid' | 'active_snapshot_conflict' | 'base_subscription_conflict' | 'serialization_conflict';
|
|
35
|
+
export declare class BillingSubscriptionReconciliationConflictError extends Error {
|
|
36
|
+
readonly code: BillingSubscriptionReconciliationConflictCode;
|
|
37
|
+
constructor(code: BillingSubscriptionReconciliationConflictCode, message: string);
|
|
38
|
+
}
|
|
39
|
+
export declare function billingSubscriptionReconciliationContractError(message?: string): BillingSubscriptionReconciliationConflictError;
|
|
40
|
+
export declare function requireCurrentlyEffectivePaidSubscription(revision: BillingBaseSubscriptionRevisionRecord, databaseTime: string): void;
|
|
41
|
+
export declare function normalizeBillingSubscriptionReconciliationRequest(input: BillingSubscriptionReconciliationRequest): NormalizedBillingSubscriptionReconciliationRequest;
|
|
42
|
+
export declare function billingSubscriptionReconciliationRequestFingerprint(request: NormalizedBillingSubscriptionReconciliationRequest): string;
|
|
43
|
+
export declare function parseBillingSubscriptionReconciliationResult(value: unknown): BillingSubscriptionReconciliationResult;
|
|
44
|
+
export declare function billingSubscriptionReconciliationSuccessAudit(result: BillingSubscriptionReconciliationResult): AuditEventInput;
|
|
45
|
+
//# sourceMappingURL=subscription-reconciliation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-reconciliation.d.ts","sourceRoot":"","sources":["../../src/billing/subscription-reconciliation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,EACL,KAAK,oCAAoC,EACzC,KAAK,qCAAqC,EAG3C,MAAM,yBAAyB,CAAC;AAEjC,eAAO,MAAM,uCAAuC,EAAG,CAAU,CAAC;AAElE,MAAM,WAAW,yCAAyC;IACxD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,wCAAwC;IACvD,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,6BAA6B,EAAE,MAAM,CAAC;IAC/C,QAAQ,CAAC,+BAA+B,EAAE,yCAAyC,GAAG,IAAI,CAAC;IAC3F,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,oCAAoC,CAAC;CACzD;AAED,MAAM,WAAW,kDACf,SAAQ,IAAI,CAAC,wCAAwC,EAAE,UAAU,CAAC;IAClE,QAAQ,CAAC,QAAQ,EAAE,qCAAqC,CAAC;CAC1D;AAED,MAAM,WAAW,uCAAuC;IACtD,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,2BAA2B,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,sCAAsC;IACrD,yBAAyB,CACvB,OAAO,EAAE,wCAAwC,GAChD,OAAO,CAAC,uCAAuC,CAAC,CAAC;CACrD;AAED,MAAM,MAAM,6CAA6C,GACrD,0BAA0B,GAC1B,qCAAqC,GACrC,0BAA0B,GAC1B,8BAA8B,GAC9B,yCAAyC,GACzC,oCAAoC,GACpC,8BAA8B,GAC9B,0BAA0B,GAC1B,4BAA4B,GAC5B,wBAAwB,CAAC;AAE7B,qBAAa,8CAA+C,SAAQ,KAAK;IACvE,QAAQ,CAAC,IAAI,EAAE,6CAA6C,CAAC;gBAEjD,IAAI,EAAE,6CAA6C,EAAE,OAAO,EAAE,MAAM;CAKjF;AAED,wBAAgB,8CAA8C,CAC5D,OAAO,SAA6E,GACnF,8CAA8C,CAKhD;AAED,wBAAgB,yCAAyC,CACvD,QAAQ,EAAE,qCAAqC,EAC/C,YAAY,EAAE,MAAM,GACnB,IAAI,CAgBN;AAED,wBAAgB,iDAAiD,CAC/D,KAAK,EAAE,wCAAwC,GAC9C,kDAAkD,CAsCpD;AAED,wBAAgB,mDAAmD,CACjE,OAAO,EAAE,kDAAkD,GAC1D,MAAM,CASR;AAED,wBAAgB,4CAA4C,CAC1D,KAAK,EAAE,OAAO,GACb,uCAAuC,CAyBzC;AAED,wBAAgB,6CAA6C,CAC3D,MAAM,EAAE,uCAAuC,GAC9C,eAAe,CAcjB"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { billingContentChecksum, validateBillingAccountId } from './model.js';
|
|
2
|
+
import { getBillingPublicPlanVersion } from './paid-plan-catalog.js';
|
|
3
|
+
import { createBillingBaseSubscriptionRevision, validateBillingSubscriptionId, } from './subscription-model.js';
|
|
4
|
+
export const BILLING_PAID_ADMISSION_CONTRACT_VERSION = 2;
|
|
5
|
+
export class BillingSubscriptionReconciliationConflictError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
constructor(code, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = 'BillingSubscriptionReconciliationConflictError';
|
|
10
|
+
this.code = code;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function billingSubscriptionReconciliationContractError(message = 'paid subscription reconciliation violates the active commercial contract') {
|
|
14
|
+
return new BillingSubscriptionReconciliationConflictError('paid_subscription_contract_invalid', message);
|
|
15
|
+
}
|
|
16
|
+
export function requireCurrentlyEffectivePaidSubscription(revision, databaseTime) {
|
|
17
|
+
const now = canonicalInstant('subscription reconciliation database time', databaseTime);
|
|
18
|
+
const plan = getBillingPublicPlanVersion(revision.planVersionId);
|
|
19
|
+
if (plan === undefined ||
|
|
20
|
+
plan.planCode === 'free' ||
|
|
21
|
+
plan.effectiveFrom > revision.effectiveFrom ||
|
|
22
|
+
revision.effectiveFrom > now ||
|
|
23
|
+
now >= revision.effectiveUntil ||
|
|
24
|
+
revision.verifiedAt > now ||
|
|
25
|
+
revision.createdAt > now) {
|
|
26
|
+
throw billingSubscriptionReconciliationContractError('paid subscription reconciliation requires currently effective verified access');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function normalizeBillingSubscriptionReconciliationRequest(input) {
|
|
30
|
+
if (input.schemaVersion !== 1) {
|
|
31
|
+
throw new Error('billing subscription reconciliation schema is invalid');
|
|
32
|
+
}
|
|
33
|
+
const billingAccountId = validateBillingAccountId(input.billingAccountId);
|
|
34
|
+
const revision = createBillingBaseSubscriptionRevision(input.revision);
|
|
35
|
+
if (revision.billingAccountId !== billingAccountId) {
|
|
36
|
+
throw new Error('subscription reconciliation must preserve its billing account');
|
|
37
|
+
}
|
|
38
|
+
if (revision.state !== 'active') {
|
|
39
|
+
throw new Error('paid subscription reconciliation currently requires active access');
|
|
40
|
+
}
|
|
41
|
+
const expectedActiveSnapshotVersion = positiveInteger('expected active snapshot version', input.expectedActiveSnapshotVersion);
|
|
42
|
+
const expectedCurrentBaseSubscription = normalizeCurrentSubscriptionExpectation(input.expectedCurrentBaseSubscription);
|
|
43
|
+
if (expectedCurrentBaseSubscription === null) {
|
|
44
|
+
if (revision.version !== 1) {
|
|
45
|
+
throw new Error('the first subscription reconciliation must create revision one');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if (expectedCurrentBaseSubscription.subscriptionId !== revision.subscriptionId ||
|
|
49
|
+
revision.version !== expectedCurrentBaseSubscription.revisionVersion + 1) {
|
|
50
|
+
throw new Error('subscription reconciliation revisions must be sequential');
|
|
51
|
+
}
|
|
52
|
+
return Object.freeze({
|
|
53
|
+
schemaVersion: 1,
|
|
54
|
+
billingAccountId,
|
|
55
|
+
idempotencyKey: scalar('idempotency key', input.idempotencyKey),
|
|
56
|
+
expectedActiveSnapshotVersion,
|
|
57
|
+
expectedCurrentBaseSubscription,
|
|
58
|
+
snapshotId: validateSnapshotId(input.snapshotId),
|
|
59
|
+
revision,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export function billingSubscriptionReconciliationRequestFingerprint(request) {
|
|
63
|
+
return billingContentChecksum({
|
|
64
|
+
schemaVersion: request.schemaVersion,
|
|
65
|
+
billingAccountId: request.billingAccountId,
|
|
66
|
+
expectedActiveSnapshotVersion: request.expectedActiveSnapshotVersion,
|
|
67
|
+
expectedCurrentBaseSubscription: request.expectedCurrentBaseSubscription,
|
|
68
|
+
snapshotId: request.snapshotId,
|
|
69
|
+
revision: request.revision,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export function parseBillingSubscriptionReconciliationResult(value) {
|
|
73
|
+
const input = requireRecord('billing subscription reconciliation result', value);
|
|
74
|
+
if (input.schemaVersion !== 1) {
|
|
75
|
+
throw new Error('billing subscription reconciliation result schema is invalid');
|
|
76
|
+
}
|
|
77
|
+
return Object.freeze({
|
|
78
|
+
schemaVersion: 1,
|
|
79
|
+
billingAccountId: validateBillingAccountId(requireString(input, 'billingAccountId')),
|
|
80
|
+
subscriptionId: validateBillingSubscriptionId(requireString(input, 'subscriptionId')),
|
|
81
|
+
subscriptionRevisionVersion: positiveInteger('subscription revision version', requireNumber(input, 'subscriptionRevisionVersion')),
|
|
82
|
+
snapshotId: validateSnapshotId(requireString(input, 'snapshotId')),
|
|
83
|
+
snapshotVersion: positiveInteger('entitlement snapshot version', requireNumber(input, 'snapshotVersion')),
|
|
84
|
+
planVersionId: scalar('plan version id', requireString(input, 'planVersionId')),
|
|
85
|
+
reconciledAt: canonicalInstant('subscription reconciliation time', requireString(input, 'reconciledAt')),
|
|
86
|
+
replayed: requireBoolean(input, 'replayed'),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export function billingSubscriptionReconciliationSuccessAudit(result) {
|
|
90
|
+
return {
|
|
91
|
+
eventType: 'billing.subscription.reconciled',
|
|
92
|
+
org: 'platform',
|
|
93
|
+
actorSubject: 'system:billing-subscription-reconciliation',
|
|
94
|
+
decision: 'allow',
|
|
95
|
+
status: 201,
|
|
96
|
+
details: {
|
|
97
|
+
billingAccountId: result.billingAccountId,
|
|
98
|
+
planVersionId: result.planVersionId,
|
|
99
|
+
snapshotVersion: result.snapshotVersion,
|
|
100
|
+
subscriptionRevisionVersion: result.subscriptionRevisionVersion,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function normalizeCurrentSubscriptionExpectation(input) {
|
|
105
|
+
if (input === null)
|
|
106
|
+
return null;
|
|
107
|
+
return Object.freeze({
|
|
108
|
+
subscriptionId: validateBillingSubscriptionId(input.subscriptionId),
|
|
109
|
+
revisionVersion: positiveInteger('expected subscription revision version', input.revisionVersion),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function validateSnapshotId(value) {
|
|
113
|
+
if (!/^es_[0-9a-f-]{36}$/.test(value))
|
|
114
|
+
throw new Error('invalid entitlement snapshot id');
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
function positiveInteger(name, value) {
|
|
118
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
119
|
+
throw new Error(`${name} must be positive`);
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
function canonicalInstant(name, value) {
|
|
123
|
+
const date = new Date(value);
|
|
124
|
+
if (!Number.isFinite(date.getTime()))
|
|
125
|
+
throw new Error(`${name} must be an ISO-8601 instant`);
|
|
126
|
+
return date.toISOString();
|
|
127
|
+
}
|
|
128
|
+
function scalar(name, value) {
|
|
129
|
+
const normalized = value.trim();
|
|
130
|
+
if (normalized.length === 0 ||
|
|
131
|
+
normalized.length > 512 ||
|
|
132
|
+
normalized !== value ||
|
|
133
|
+
[...normalized].some((character) => {
|
|
134
|
+
const code = character.charCodeAt(0);
|
|
135
|
+
return code <= 0x1f || code === 0x7f;
|
|
136
|
+
})) {
|
|
137
|
+
throw new Error(`${name} must be a non-empty scalar identifier`);
|
|
138
|
+
}
|
|
139
|
+
return normalized;
|
|
140
|
+
}
|
|
141
|
+
function requireRecord(name, value) {
|
|
142
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
143
|
+
throw new Error(`${name} must be an object`);
|
|
144
|
+
}
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
function requireString(record, key) {
|
|
148
|
+
const value = record[key];
|
|
149
|
+
if (typeof value !== 'string')
|
|
150
|
+
throw new Error(`${key} must be a string`);
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
function requireNumber(record, key) {
|
|
154
|
+
const value = record[key];
|
|
155
|
+
if (typeof value !== 'number')
|
|
156
|
+
throw new Error(`${key} must be a number`);
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
function requireBoolean(record, key) {
|
|
160
|
+
const value = record[key];
|
|
161
|
+
if (typeof value !== 'boolean')
|
|
162
|
+
throw new Error(`${key} must be a boolean`);
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=subscription-reconciliation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-reconciliation.js","sourceRoot":"","sources":["../../src/billing/subscription-reconciliation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAGL,qCAAqC,EACrC,6BAA6B,GAC9B,MAAM,yBAAyB,CAAC;AAEjC,MAAM,CAAC,MAAM,uCAAuC,GAAG,CAAU,CAAC;AAoDlE,MAAM,OAAO,8CAA+C,SAAQ,KAAK;IAC9D,IAAI,CAAgD;IAE7D,YAAY,IAAmD,EAAE,OAAe;QAC9E,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gDAAgD,CAAC;QAC7D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,UAAU,8CAA8C,CAC5D,OAAO,GAAG,0EAA0E;IAEpF,OAAO,IAAI,8CAA8C,CACvD,oCAAoC,EACpC,OAAO,CACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yCAAyC,CACvD,QAA+C,EAC/C,YAAoB;IAEpB,MAAM,GAAG,GAAG,gBAAgB,CAAC,2CAA2C,EAAE,YAAY,CAAC,CAAC;IACxF,MAAM,IAAI,GAAG,2BAA2B,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACjE,IACE,IAAI,KAAK,SAAS;QAClB,IAAI,CAAC,QAAQ,KAAK,MAAM;QACxB,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,aAAa;QAC3C,QAAQ,CAAC,aAAa,GAAG,GAAG;QAC5B,GAAG,IAAI,QAAQ,CAAC,cAAc;QAC9B,QAAQ,CAAC,UAAU,GAAG,GAAG;QACzB,QAAQ,CAAC,SAAS,GAAG,GAAG,EACxB,CAAC;QACD,MAAM,8CAA8C,CAClD,+EAA+E,CAChF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iDAAiD,CAC/D,KAA+C;IAE/C,IAAI,KAAK,CAAC,aAAa,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,gBAAgB,GAAG,wBAAwB,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAG,qCAAqC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACvE,IAAI,QAAQ,CAAC,gBAAgB,KAAK,gBAAgB,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;IACnF,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,6BAA6B,GAAG,eAAe,CACnD,kCAAkC,EAClC,KAAK,CAAC,6BAA6B,CACpC,CAAC;IACF,MAAM,+BAA+B,GAAG,uCAAuC,CAC7E,KAAK,CAAC,+BAA+B,CACtC,CAAC;IACF,IAAI,+BAA+B,KAAK,IAAI,EAAE,CAAC;QAC7C,IAAI,QAAQ,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;SAAM,IACL,+BAA+B,CAAC,cAAc,KAAK,QAAQ,CAAC,cAAc;QAC1E,QAAQ,CAAC,OAAO,KAAK,+BAA+B,CAAC,eAAe,GAAG,CAAC,EACxE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,aAAa,EAAE,CAAC;QAChB,gBAAgB;QAChB,cAAc,EAAE,MAAM,CAAC,iBAAiB,EAAE,KAAK,CAAC,cAAc,CAAC;QAC/D,6BAA6B;QAC7B,+BAA+B;QAC/B,UAAU,EAAE,kBAAkB,CAAC,KAAK,CAAC,UAAU,CAAC;QAChD,QAAQ;KACT,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mDAAmD,CACjE,OAA2D;IAE3D,OAAO,sBAAsB,CAAC;QAC5B,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,6BAA6B,EAAE,OAAO,CAAC,6BAA6B;QACpE,+BAA+B,EAAE,OAAO,CAAC,+BAA+B;QACxE,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,4CAA4C,CAC1D,KAAc;IAEd,MAAM,KAAK,GAAG,aAAa,CAAC,4CAA4C,EAAE,KAAK,CAAC,CAAC;IACjF,IAAI,KAAK,CAAC,aAAa,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,aAAa,EAAE,CAAC;QAChB,gBAAgB,EAAE,wBAAwB,CAAC,aAAa,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;QACpF,cAAc,EAAE,6BAA6B,CAAC,aAAa,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;QACrF,2BAA2B,EAAE,eAAe,CAC1C,+BAA+B,EAC/B,aAAa,CAAC,KAAK,EAAE,6BAA6B,CAAC,CACpD;QACD,UAAU,EAAE,kBAAkB,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QAClE,eAAe,EAAE,eAAe,CAC9B,8BAA8B,EAC9B,aAAa,CAAC,KAAK,EAAE,iBAAiB,CAAC,CACxC;QACD,aAAa,EAAE,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QAC/E,YAAY,EAAE,gBAAgB,CAC5B,kCAAkC,EAClC,aAAa,CAAC,KAAK,EAAE,cAAc,CAAC,CACrC;QACD,QAAQ,EAAE,cAAc,CAAC,KAAK,EAAE,UAAU,CAAC;KAC5C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,6CAA6C,CAC3D,MAA+C;IAE/C,OAAO;QACL,SAAS,EAAE,iCAAiC;QAC5C,GAAG,EAAE,UAAU;QACf,YAAY,EAAE,4CAA4C;QAC1D,QAAQ,EAAE,OAAO;QACjB,MAAM,EAAE,GAAG;QACX,OAAO,EAAE;YACP,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;YACzC,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,2BAA2B,EAAE,MAAM,CAAC,2BAA2B;SAChE;KACF,CAAC;AACJ,CAAC;AAED,SAAS,uCAAuC,CAC9C,KAAuD;IAEvD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,cAAc,EAAE,6BAA6B,CAAC,KAAK,CAAC,cAAc,CAAC;QACnE,eAAe,EAAE,eAAe,CAC9B,wCAAwC,EACxC,KAAK,CAAC,eAAe,CACtB;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAa;IACvC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC1F,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,KAAa;IAClD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,mBAAmB,CAAC,CAAC;IAC3F,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY,EAAE,KAAa;IACnD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,8BAA8B,CAAC,CAAC;IAC7F,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,MAAM,CAAC,IAAY,EAAE,KAAa;IACzC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAChC,IACE,UAAU,CAAC,MAAM,KAAK,CAAC;QACvB,UAAU,CAAC,MAAM,GAAG,GAAG;QACvB,UAAU,KAAK,KAAK;QACpB,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YACjC,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YACrC,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC;QACvC,CAAC,CAAC,EACF,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,wCAAwC,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,aAAa,CAAC,IAAY,EAAE,KAAc;IACjD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,oBAAoB,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,KAAgC,CAAC;AAC1C,CAAC;AAED,SAAS,aAAa,CAAC,MAA+B,EAAE,GAAW;IACjE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,mBAAmB,CAAC,CAAC;IAC1E,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,MAA+B,EAAE,GAAW;IACjE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,mBAAmB,CAAC,CAAC;IAC1E,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CAAC,MAA+B,EAAE,GAAW;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,oBAAoB,CAAC,CAAC;IAC5E,OAAO,KAAK,CAAC;AACf,CAAC"}
|