@noodleseed/one 0.53.0 → 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/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/paid-plan-catalog.d.ts +1 -0
- package/node_modules/@noodle-borg/service/dist/billing/paid-plan-catalog.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/paid-plan-catalog.js +7 -0
- package/node_modules/@noodle-borg/service/dist/billing/paid-plan-catalog.js.map +1 -1
- 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-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.js +100 -0
- package/node_modules/@noodle-borg/service/dist/billing/postgres-subscription-schema.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/subscription-model.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing/subscription-model.js +9 -1
- package/node_modules/@noodle-borg/service/dist/billing/subscription-model.js.map +1 -1
- 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 +2 -0
- package/node_modules/@noodle-borg/service/dist/billing-public.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/billing-public.js +2 -0
- package/node_modules/@noodle-borg/service/dist/billing-public.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BillingActiveCommercialEntitlementInconsistentError, resolveActiveBillingCommercialEntitlement, } from './active-commercial-entitlement.js';
|
|
2
2
|
import { billingContentChecksum } from './model.js';
|
|
3
|
+
import { readBillingMeterTransactionTime } from './postgres-meter-clock.js';
|
|
3
4
|
/**
|
|
4
5
|
* This exact deployed lock identity is shared with validation-epoch lifecycle operations. Keeping the
|
|
5
6
|
* value stable makes old and new service revisions serialize during a rolling enforcement cutover.
|
|
6
7
|
*/
|
|
7
8
|
export const BILLING_ENFORCEMENT_LIFECYCLE_LOCK_KEY = 'billing-meter-validation-epoch-lifecycle:v1';
|
|
8
|
-
const PRODUCTION_APP_ADMISSION_CONTRACT_VERSION = 1;
|
|
9
9
|
export class BillingProductionAppAdmissionError extends Error {
|
|
10
10
|
code;
|
|
11
11
|
constructor(code) {
|
|
@@ -42,11 +42,11 @@ export async function prepareProductionAppAdmissionTx(client, input) {
|
|
|
42
42
|
}
|
|
43
43
|
throw error;
|
|
44
44
|
}
|
|
45
|
-
if (authorityMode === 'bypass')
|
|
45
|
+
if (authorityMode.mode === 'bypass')
|
|
46
46
|
return { kind: 'bypass' };
|
|
47
|
-
return resolveProductionAppAdmissionTx(client, input);
|
|
47
|
+
return resolveProductionAppAdmissionTx(client, input, authorityMode.admissionContractVersion);
|
|
48
48
|
}
|
|
49
|
-
async function resolveProductionAppAdmissionTx(client, input) {
|
|
49
|
+
async function resolveProductionAppAdmissionTx(client, input, admissionContractVersion) {
|
|
50
50
|
const initialLink = await client.query(`SELECT billing_account_id
|
|
51
51
|
FROM org_billing_links
|
|
52
52
|
WHERE org_slug = $1 AND active`, [input.org]);
|
|
@@ -62,6 +62,17 @@ async function resolveProductionAppAdmissionTx(client, input) {
|
|
|
62
62
|
profile.cohort_seal_id AS profile_cohort_seal_id,
|
|
63
63
|
profile.effective_from AS profile_effective_from,
|
|
64
64
|
seal.id AS cohort_seal_id, seal.sealed_at AS cohort_sealed_at,
|
|
65
|
+
snapshot.id, snapshot.version, snapshot.plan_version_id,
|
|
66
|
+
plan.plan_code, plan.version AS plan_version,
|
|
67
|
+
plan.effective_from AS plan_effective_from,
|
|
68
|
+
plan.entitlements AS plan_entitlements,
|
|
69
|
+
plan.content_checksum AS plan_content_checksum,
|
|
70
|
+
plan.created_at AS plan_created_at,
|
|
71
|
+
snapshot.schema_version, snapshot.source_kind, snapshot.generation_reason,
|
|
72
|
+
snapshot.verification_status, snapshot.effective_from, snapshot.effective_until,
|
|
73
|
+
snapshot.monthly_usage_anchor, snapshot.entitlements, snapshot.content_checksum,
|
|
74
|
+
snapshot.source_subscription_id, snapshot.source_subscription_version,
|
|
75
|
+
snapshot.verified_at, snapshot.created_at,
|
|
65
76
|
snapshot.id AS snapshot_id, snapshot.version AS snapshot_version,
|
|
66
77
|
snapshot.plan_version_id AS snapshot_plan_version_id,
|
|
67
78
|
snapshot.verification_status AS snapshot_verification_status,
|
|
@@ -76,6 +87,7 @@ async function resolveProductionAppAdmissionTx(client, input) {
|
|
|
76
87
|
JOIN billing_entitlement_snapshots AS snapshot
|
|
77
88
|
ON snapshot.billing_account_id = active_snapshot.billing_account_id
|
|
78
89
|
AND snapshot.id = active_snapshot.snapshot_id
|
|
90
|
+
JOIN billing_plan_versions AS plan ON plan.id = snapshot.plan_version_id
|
|
79
91
|
JOIN billing_account_active_enforcement_profiles AS active_profile
|
|
80
92
|
ON active_profile.billing_account_id = link.billing_account_id
|
|
81
93
|
JOIN billing_account_enforcement_profiles AS profile
|
|
@@ -84,14 +96,30 @@ async function resolveProductionAppAdmissionTx(client, input) {
|
|
|
84
96
|
JOIN billing_enforcement_cohort_seals AS seal ON seal.singleton = true
|
|
85
97
|
WHERE link.org_slug = $1
|
|
86
98
|
AND link.active
|
|
87
|
-
FOR SHARE OF link, account, active_snapshot, snapshot, active_profile, profile, seal`, [input.org]);
|
|
99
|
+
FOR SHARE OF link, account, active_snapshot, snapshot, plan, active_profile, profile, seal`, [input.org]);
|
|
88
100
|
const row = resolution.rows[0];
|
|
89
101
|
if (row === undefined || row.billing_account_id !== initialAccountId)
|
|
90
102
|
throw unavailable();
|
|
91
|
-
|
|
92
|
-
if (row.mode === 'legacy_internal_exempt')
|
|
103
|
+
validateBillingResolutionProfile(row);
|
|
104
|
+
if (row.mode === 'legacy_internal_exempt') {
|
|
105
|
+
validateLegacyBillingResolution(row);
|
|
93
106
|
return { kind: 'bypass' };
|
|
94
|
-
|
|
107
|
+
}
|
|
108
|
+
if (admissionContractVersion === undefined)
|
|
109
|
+
throw unavailable();
|
|
110
|
+
const databaseTime = await readBillingMeterTransactionTime(client);
|
|
111
|
+
let entitlements;
|
|
112
|
+
try {
|
|
113
|
+
entitlements = resolveActiveBillingCommercialEntitlement(row, {
|
|
114
|
+
admissionContractVersion,
|
|
115
|
+
databaseTime,
|
|
116
|
+
}).entitlements;
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
if (error instanceof BillingActiveCommercialEntitlementInconsistentError)
|
|
120
|
+
throw unavailable();
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
95
123
|
return {
|
|
96
124
|
kind: 'enforced',
|
|
97
125
|
billingAccountId: row.billing_account_id,
|
|
@@ -173,40 +201,45 @@ function validateAuthority(row) {
|
|
|
173
201
|
authoritativeActiveCount !== 0) {
|
|
174
202
|
throw unavailable();
|
|
175
203
|
}
|
|
176
|
-
return 'bypass';
|
|
204
|
+
return { mode: 'bypass' };
|
|
177
205
|
}
|
|
178
206
|
if (row.activation_state === 'rolled_back') {
|
|
207
|
+
const admissionContractVersion = persistedAdmissionContractVersion(row.activation_contract_version);
|
|
179
208
|
if (row.activation_generation < 1 ||
|
|
180
209
|
row.active_epoch_id !== null ||
|
|
181
210
|
row.last_epoch_id === null ||
|
|
182
|
-
row.activation_contract_version !== PRODUCTION_APP_ADMISSION_CONTRACT_VERSION ||
|
|
183
211
|
row.last_epoch_purpose !== 'authoritative' ||
|
|
184
212
|
row.last_epoch_state !== 'retired' ||
|
|
185
|
-
row.last_epoch_contract_version !==
|
|
213
|
+
row.last_epoch_contract_version !== admissionContractVersion ||
|
|
186
214
|
row.last_epoch_release_sha !== row.activation_release_sha ||
|
|
187
215
|
!sameInstant(row.last_epoch_activated_at, row.activation_activated_at) ||
|
|
188
216
|
authoritativeActiveCount !== 0) {
|
|
189
217
|
throw unavailable();
|
|
190
218
|
}
|
|
191
|
-
return 'bypass';
|
|
219
|
+
return { mode: 'bypass' };
|
|
192
220
|
}
|
|
221
|
+
const admissionContractVersion = persistedAdmissionContractVersion(row.activation_contract_version);
|
|
193
222
|
if (row.activation_state !== 'active' ||
|
|
194
223
|
row.activation_generation < 1 ||
|
|
195
224
|
row.active_epoch_id === null ||
|
|
196
225
|
row.active_epoch_id !== row.last_epoch_id ||
|
|
197
|
-
row.activation_contract_version !== PRODUCTION_APP_ADMISSION_CONTRACT_VERSION ||
|
|
198
226
|
row.active_epoch_purpose !== 'authoritative' ||
|
|
199
227
|
row.active_epoch_state !== 'active' ||
|
|
200
|
-
row.active_epoch_contract_version !==
|
|
228
|
+
row.active_epoch_contract_version !== admissionContractVersion ||
|
|
201
229
|
row.active_epoch_release_sha !== row.activation_release_sha ||
|
|
202
230
|
!sameInstant(row.active_epoch_activated_at, row.activation_activated_at) ||
|
|
203
231
|
row.active_epoch_reconciliation_failed_at !== null ||
|
|
204
232
|
authoritativeActiveCount !== 1) {
|
|
205
233
|
throw unavailable();
|
|
206
234
|
}
|
|
207
|
-
return 'enforce';
|
|
235
|
+
return { mode: 'enforce', admissionContractVersion };
|
|
208
236
|
}
|
|
209
|
-
function
|
|
237
|
+
function persistedAdmissionContractVersion(value) {
|
|
238
|
+
if (value !== 1 && value !== 2)
|
|
239
|
+
throw unavailable();
|
|
240
|
+
return value;
|
|
241
|
+
}
|
|
242
|
+
function validateBillingResolutionProfile(row) {
|
|
210
243
|
const profileEffectiveFrom = persistedInstant(row.profile_effective_from);
|
|
211
244
|
const cohortSealedAt = persistedInstant(row.cohort_sealed_at);
|
|
212
245
|
const validLegacyProfile = row.mode === 'legacy_internal_exempt' &&
|
|
@@ -217,7 +250,12 @@ function validateBillingResolution(row) {
|
|
|
217
250
|
profileEffectiveFrom >= cohortSealedAt;
|
|
218
251
|
if (row.account_state !== 'active' ||
|
|
219
252
|
row.profile_cohort_seal_id !== row.cohort_seal_id ||
|
|
220
|
-
(!validLegacyProfile && !validEnforcedProfile)
|
|
253
|
+
(!validLegacyProfile && !validEnforcedProfile)) {
|
|
254
|
+
throw unavailable();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function validateLegacyBillingResolution(row) {
|
|
258
|
+
if (row.mode !== 'legacy_internal_exempt' ||
|
|
221
259
|
row.snapshot_verification_status !== 'verified' ||
|
|
222
260
|
!Number.isSafeInteger(row.snapshot_version) ||
|
|
223
261
|
row.snapshot_version < 1) {
|
|
@@ -235,14 +273,6 @@ function validateBillingResolution(row) {
|
|
|
235
273
|
});
|
|
236
274
|
if (row.snapshot_content_checksum !== expectedChecksum)
|
|
237
275
|
throw unavailable();
|
|
238
|
-
if (row.mode === 'enforced') {
|
|
239
|
-
try {
|
|
240
|
-
parseBillingCommercialFreeV1Entitlements(row.entitlements);
|
|
241
|
-
}
|
|
242
|
-
catch {
|
|
243
|
-
throw unavailable();
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
276
|
}
|
|
247
277
|
function sameInstant(left, right) {
|
|
248
278
|
if (left === null || right === null)
|
package/node_modules/@noodle-borg/service/dist/billing/postgres-production-app-admission.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-production-app-admission.js","sourceRoot":"","sources":["../../src/billing/postgres-production-app-admission.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"postgres-production-app-admission.js","sourceRoot":"","sources":["../../src/billing/postgres-production-app-admission.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PoolClient } from 'pg';
|
|
2
|
+
export declare function requirePaidAuthority(client: PoolClient, key: string): Promise<void>;
|
|
3
|
+
export declare function requireActiveBillingAccount(client: PoolClient, billingAccountId: string): Promise<void>;
|
|
4
|
+
export declare function requireEnforcedBillingAccount(client: PoolClient, billingAccountId: string): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=postgres-subscription-reconciliation-authority.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-subscription-reconciliation-authority.d.ts","sourceRoot":"","sources":["../../src/billing/postgres-subscription-reconciliation-authority.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAyBrC,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBzF;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,UAAU,EAClB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,UAAU,EAClB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CA6Ef"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { BillingAuthoritativeAuthorityInconsistentError, readBillingAuthoritativeAuthorityTx, } from './postgres-authoritative-authority.js';
|
|
2
|
+
import { conflict } from './postgres-subscription-reconciliation-support.js';
|
|
3
|
+
import { BILLING_PAID_ADMISSION_CONTRACT_VERSION } from './subscription-reconciliation.js';
|
|
4
|
+
export async function requirePaidAuthority(client, key) {
|
|
5
|
+
try {
|
|
6
|
+
const authority = await readBillingAuthoritativeAuthorityTx(client, { keyGeneration: key });
|
|
7
|
+
if (authority.state !== 'active' ||
|
|
8
|
+
authority.admissionContractVersion !== BILLING_PAID_ADMISSION_CONTRACT_VERSION) {
|
|
9
|
+
throw conflict('paid_admission_contract_unavailable', 'paid subscription activation requires active commercial admission contract v2');
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error instanceof BillingAuthoritativeAuthorityInconsistentError) {
|
|
14
|
+
throw conflict('paid_admission_contract_unavailable', 'paid subscription activation requires coherent commercial admission authority');
|
|
15
|
+
}
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function requireActiveBillingAccount(client, billingAccountId) {
|
|
20
|
+
const { rows } = await client.query(`SELECT state FROM billing_accounts WHERE id = $1 FOR UPDATE`, [billingAccountId]);
|
|
21
|
+
if (rows[0]?.state !== 'active') {
|
|
22
|
+
throw conflict('billing_account_conflict', 'paid subscription reconciliation requires an active billing account');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function requireEnforcedBillingAccount(client, billingAccountId) {
|
|
26
|
+
const { rows } = await client.query(`SELECT seal.id AS seal_id,
|
|
27
|
+
seal.schema_version AS seal_schema_version,
|
|
28
|
+
seal.cohort_kind AS seal_cohort_kind,
|
|
29
|
+
seal.state AS seal_state,
|
|
30
|
+
seal.post_seal_account_profile AS seal_post_profile,
|
|
31
|
+
seal.sealed_at,
|
|
32
|
+
active.profile_version AS active_profile_version,
|
|
33
|
+
profile.schema_version AS profile_schema_version,
|
|
34
|
+
profile.mode AS profile_mode,
|
|
35
|
+
profile.cohort_kind AS profile_cohort_kind,
|
|
36
|
+
profile.cohort_seal_id AS profile_cohort_seal_id,
|
|
37
|
+
profile.source AS profile_source,
|
|
38
|
+
profile.effective_from AS profile_effective_from,
|
|
39
|
+
profile.created_at AS profile_created_at
|
|
40
|
+
FROM billing_enforcement_cohort_seals AS seal
|
|
41
|
+
LEFT JOIN billing_account_active_enforcement_profiles AS active
|
|
42
|
+
ON active.billing_account_id = $1
|
|
43
|
+
LEFT JOIN billing_account_enforcement_profiles AS profile
|
|
44
|
+
ON profile.billing_account_id = active.billing_account_id
|
|
45
|
+
AND profile.version = active.profile_version
|
|
46
|
+
WHERE seal.singleton = true`, [billingAccountId]);
|
|
47
|
+
const profile = rows[0];
|
|
48
|
+
if (profile === undefined || !profileBindingIsComplete(profile)) {
|
|
49
|
+
throw conflict('billing_account_enforcement_unavailable', 'paid subscription activation requires a coherent active enforcement profile');
|
|
50
|
+
}
|
|
51
|
+
const sharedProfileIsCoherent = profile.seal_schema_version === 1 &&
|
|
52
|
+
profile.seal_cohort_kind === 'legacy_internal_v1' &&
|
|
53
|
+
profile.seal_state === 'sealed' &&
|
|
54
|
+
profile.seal_post_profile === 'enforced' &&
|
|
55
|
+
profile.profile_schema_version === 1 &&
|
|
56
|
+
profile.profile_cohort_kind === profile.seal_cohort_kind &&
|
|
57
|
+
profile.profile_cohort_seal_id === profile.seal_id;
|
|
58
|
+
if (!sharedProfileIsCoherent) {
|
|
59
|
+
throw conflict('billing_account_enforcement_unavailable', 'paid subscription activation requires a coherent active enforcement profile');
|
|
60
|
+
}
|
|
61
|
+
const sealedAt = toIso(profile.sealed_at);
|
|
62
|
+
const effectiveFrom = toIso(profile.profile_effective_from);
|
|
63
|
+
const createdAt = toIso(profile.profile_created_at);
|
|
64
|
+
if (profile.profile_mode === 'legacy_internal_exempt') {
|
|
65
|
+
if (profile.profile_source !== 'legacy_cohort_seal' ||
|
|
66
|
+
effectiveFrom !== sealedAt ||
|
|
67
|
+
createdAt !== sealedAt) {
|
|
68
|
+
throw conflict('billing_account_enforcement_unavailable', 'paid subscription activation requires a coherent active enforcement profile');
|
|
69
|
+
}
|
|
70
|
+
throw conflict('billing_account_not_enforced', 'legacy internal exempt billing accounts cannot activate paid subscriptions');
|
|
71
|
+
}
|
|
72
|
+
if (profile.profile_mode !== 'enforced' ||
|
|
73
|
+
profile.profile_source !== 'post_seal_account' ||
|
|
74
|
+
effectiveFrom < sealedAt ||
|
|
75
|
+
createdAt !== effectiveFrom) {
|
|
76
|
+
throw conflict('billing_account_enforcement_unavailable', 'paid subscription activation requires a coherent active enforcement profile');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function profileBindingIsComplete(profile) {
|
|
80
|
+
return (Number.isSafeInteger(profile.active_profile_version) &&
|
|
81
|
+
(profile.active_profile_version ?? 0) > 0 &&
|
|
82
|
+
profile.profile_schema_version !== null &&
|
|
83
|
+
profile.profile_mode !== null &&
|
|
84
|
+
profile.profile_cohort_kind !== null &&
|
|
85
|
+
profile.profile_cohort_seal_id !== null &&
|
|
86
|
+
profile.profile_source !== null &&
|
|
87
|
+
profile.profile_effective_from !== null &&
|
|
88
|
+
profile.profile_created_at !== null);
|
|
89
|
+
}
|
|
90
|
+
function toIso(value) {
|
|
91
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
92
|
+
if (!Number.isFinite(date.getTime())) {
|
|
93
|
+
throw conflict('billing_account_enforcement_unavailable', 'paid subscription activation requires valid enforcement profile timestamps');
|
|
94
|
+
}
|
|
95
|
+
return date.toISOString();
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=postgres-subscription-reconciliation-authority.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-subscription-reconciliation-authority.js","sourceRoot":"","sources":["../../src/billing/postgres-subscription-reconciliation-authority.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { PoolClient } from 'pg';
|
|
2
|
+
import { entitlementSnapshotRowToRecord } from './postgres-records.js';
|
|
3
|
+
import type { createPaidEntitlementSnapshot } from './subscription-model.js';
|
|
4
|
+
import { type BillingSubscriptionReconciliationRequest, type BillingSubscriptionReconciliationResult, type normalizeBillingSubscriptionReconciliationRequest } from './subscription-reconciliation.js';
|
|
5
|
+
export interface OperationRow {
|
|
6
|
+
readonly request_fingerprint: string;
|
|
7
|
+
readonly billing_account_id: string;
|
|
8
|
+
readonly subscription_id: string;
|
|
9
|
+
readonly revision_version: number;
|
|
10
|
+
readonly snapshot_id: string;
|
|
11
|
+
readonly created_at: Date | string;
|
|
12
|
+
readonly result: unknown;
|
|
13
|
+
readonly persisted_snapshot_id: string | null;
|
|
14
|
+
readonly snapshot_version: number | null;
|
|
15
|
+
readonly plan_version_id: string | null;
|
|
16
|
+
readonly source_subscription_id: string | null;
|
|
17
|
+
readonly source_subscription_version: number | null;
|
|
18
|
+
}
|
|
19
|
+
export interface CurrentSubscriptionRow {
|
|
20
|
+
readonly subscription_id: string;
|
|
21
|
+
readonly revision_version: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function findOperation(client: PoolClient, idempotencyHash: string): Promise<OperationRow | undefined>;
|
|
24
|
+
export declare function replayOperation(row: OperationRow, fingerprint: string): {
|
|
25
|
+
replayed: boolean;
|
|
26
|
+
schemaVersion: 1;
|
|
27
|
+
billingAccountId: string;
|
|
28
|
+
subscriptionId: string;
|
|
29
|
+
subscriptionRevisionVersion: number;
|
|
30
|
+
snapshotId: string;
|
|
31
|
+
snapshotVersion: number;
|
|
32
|
+
planVersionId: string;
|
|
33
|
+
reconciledAt: string;
|
|
34
|
+
};
|
|
35
|
+
export declare function readActiveSnapshotForUpdate(client: PoolClient, billingAccountId: string): Promise<import("./model.js").EntitlementSnapshotRecord | undefined>;
|
|
36
|
+
export declare function requireNoLaterSnapshot(client: PoolClient, billingAccountId: string, activeVersion: number): Promise<void>;
|
|
37
|
+
export declare function readCurrentSubscriptionForUpdate(client: PoolClient, billingAccountId: string): Promise<CurrentSubscriptionRow | undefined>;
|
|
38
|
+
export declare function validateCurrentSubscription(current: CurrentSubscriptionRow | undefined, expected: BillingSubscriptionReconciliationRequest['expectedCurrentBaseSubscription'], previousSnapshot: ReturnType<typeof entitlementSnapshotRowToRecord>): void;
|
|
39
|
+
export declare function validateSubscriptionHistory(client: PoolClient, request: ReturnType<typeof normalizeBillingSubscriptionReconciliationRequest>, current: CurrentSubscriptionRow | undefined): Promise<void>;
|
|
40
|
+
export declare function insertRevision(client: PoolClient, revision: ReturnType<typeof normalizeBillingSubscriptionReconciliationRequest>['revision']): Promise<void>;
|
|
41
|
+
export declare function insertPaidSnapshot(client: PoolClient, snapshot: ReturnType<typeof createPaidEntitlementSnapshot>): Promise<void>;
|
|
42
|
+
export declare function compareAndSwapPointers(client: PoolClient, request: ReturnType<typeof normalizeBillingSubscriptionReconciliationRequest>, previousSnapshotId: string, current: CurrentSubscriptionRow | undefined): Promise<void>;
|
|
43
|
+
export declare function insertOperation(client: PoolClient, input: {
|
|
44
|
+
readonly operationId: string;
|
|
45
|
+
readonly idempotencyHash: string;
|
|
46
|
+
readonly fingerprint: string;
|
|
47
|
+
readonly result: BillingSubscriptionReconciliationResult;
|
|
48
|
+
readonly createdAt: string;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
//# sourceMappingURL=postgres-subscription-reconciliation-persistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-subscription-reconciliation-persistence.d.ts","sourceRoot":"","sources":["../../src/billing/postgres-subscription-reconciliation-persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,EAA+B,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EACL,KAAK,wCAAwC,EAC7C,KAAK,uCAAuC,EAC5C,KAAK,iDAAiD,EAEvD,MAAM,kCAAkC,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,IAAI,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,QAAQ,CAAC,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,UAAU,EAClB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAsBnC;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM;;;;;;;;;;EA8BrE;AASD,wBAAsB,2BAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,uEAmB7F;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,UAAU,EAClB,gBAAgB,EAAE,MAAM,EACxB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,wBAAsB,gCAAgC,CACpD,MAAM,EAAE,UAAU,EAClB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC,CAS7C;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,sBAAsB,GAAG,SAAS,EAC3C,QAAQ,EAAE,wCAAwC,CAAC,iCAAiC,CAAC,EACrF,gBAAgB,EAAE,UAAU,CAAC,OAAO,8BAA8B,CAAC,GAClE,IAAI,CAuBN;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,UAAU,CAAC,OAAO,iDAAiD,CAAC,EAC7E,OAAO,EAAE,sBAAsB,GAAG,SAAS,GAC1C,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,UAAU,CAAC,OAAO,iDAAiD,CAAC,CAAC,UAAU,CAAC,GACzF,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,UAAU,CAAC,OAAO,6BAA6B,CAAC,GACzD,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,UAAU,CAAC,OAAO,iDAAiD,CAAC,EAC7E,kBAAkB,EAAE,MAAM,EAC1B,OAAO,EAAE,sBAAsB,GAAG,SAAS,GAC1C,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE;IACL,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,uCAAuC,CAAC;IACzD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,GACA,OAAO,CAAC,IAAI,CAAC,CAkBf"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { entitlementSnapshotRowToRecord } from './postgres-records.js';
|
|
2
|
+
import { conflict } from './postgres-subscription-reconciliation-support.js';
|
|
3
|
+
import { parseBillingSubscriptionReconciliationResult, } from './subscription-reconciliation.js';
|
|
4
|
+
export async function findOperation(client, idempotencyHash) {
|
|
5
|
+
const { rows } = await client.query(`SELECT operation.request_fingerprint,
|
|
6
|
+
operation.billing_account_id,
|
|
7
|
+
operation.subscription_id,
|
|
8
|
+
operation.revision_version,
|
|
9
|
+
operation.snapshot_id,
|
|
10
|
+
operation.created_at,
|
|
11
|
+
operation.result,
|
|
12
|
+
snapshot.id AS persisted_snapshot_id,
|
|
13
|
+
snapshot.version AS snapshot_version,
|
|
14
|
+
snapshot.plan_version_id,
|
|
15
|
+
snapshot.source_subscription_id,
|
|
16
|
+
snapshot.source_subscription_version
|
|
17
|
+
FROM billing_subscription_reconciliation_operations AS operation
|
|
18
|
+
LEFT JOIN billing_entitlement_snapshots AS snapshot
|
|
19
|
+
ON snapshot.billing_account_id = operation.billing_account_id
|
|
20
|
+
AND snapshot.id = operation.snapshot_id
|
|
21
|
+
WHERE operation.idempotency_key_hash = $1`, [idempotencyHash]);
|
|
22
|
+
return rows[0];
|
|
23
|
+
}
|
|
24
|
+
export function replayOperation(row, fingerprint) {
|
|
25
|
+
if (row.request_fingerprint !== fingerprint) {
|
|
26
|
+
throw conflict('idempotency_key_conflict', 'idempotency key was already used by a different subscription reconciliation request');
|
|
27
|
+
}
|
|
28
|
+
let result;
|
|
29
|
+
try {
|
|
30
|
+
result = parseBillingSubscriptionReconciliationResult(row.result);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
throw invalidIdempotencyEvidence();
|
|
34
|
+
}
|
|
35
|
+
const createdAt = row.created_at instanceof Date ? row.created_at.toISOString() : row.created_at;
|
|
36
|
+
if (result.replayed ||
|
|
37
|
+
result.billingAccountId !== row.billing_account_id ||
|
|
38
|
+
result.subscriptionId !== row.subscription_id ||
|
|
39
|
+
result.subscriptionRevisionVersion !== row.revision_version ||
|
|
40
|
+
result.snapshotId !== row.snapshot_id ||
|
|
41
|
+
result.reconciledAt !== createdAt ||
|
|
42
|
+
row.persisted_snapshot_id !== row.snapshot_id ||
|
|
43
|
+
row.source_subscription_id !== row.subscription_id ||
|
|
44
|
+
row.source_subscription_version !== row.revision_version ||
|
|
45
|
+
result.snapshotVersion !== row.snapshot_version ||
|
|
46
|
+
result.planVersionId !== row.plan_version_id) {
|
|
47
|
+
throw invalidIdempotencyEvidence();
|
|
48
|
+
}
|
|
49
|
+
return { ...result, replayed: true };
|
|
50
|
+
}
|
|
51
|
+
function invalidIdempotencyEvidence() {
|
|
52
|
+
return conflict('idempotency_evidence_invalid', 'persisted subscription reconciliation evidence is inconsistent');
|
|
53
|
+
}
|
|
54
|
+
export async function readActiveSnapshotForUpdate(client, billingAccountId) {
|
|
55
|
+
const { rows } = await client.query(`SELECT snapshot.*,
|
|
56
|
+
plan.plan_code,
|
|
57
|
+
plan.version AS plan_version,
|
|
58
|
+
plan.effective_from AS plan_effective_from,
|
|
59
|
+
plan.entitlements AS plan_entitlements,
|
|
60
|
+
plan.content_checksum AS plan_content_checksum,
|
|
61
|
+
plan.created_at AS plan_created_at
|
|
62
|
+
FROM billing_account_active_snapshots AS active
|
|
63
|
+
JOIN billing_entitlement_snapshots AS snapshot
|
|
64
|
+
ON snapshot.billing_account_id = active.billing_account_id
|
|
65
|
+
AND snapshot.id = active.snapshot_id
|
|
66
|
+
JOIN billing_plan_versions AS plan ON plan.id = snapshot.plan_version_id
|
|
67
|
+
WHERE active.billing_account_id = $1
|
|
68
|
+
FOR UPDATE OF active, snapshot`, [billingAccountId]);
|
|
69
|
+
return rows[0] === undefined ? undefined : entitlementSnapshotRowToRecord(rows[0]);
|
|
70
|
+
}
|
|
71
|
+
export async function requireNoLaterSnapshot(client, billingAccountId, activeVersion) {
|
|
72
|
+
const { rows } = await client.query(`SELECT max(version)::integer AS latest_version
|
|
73
|
+
FROM billing_entitlement_snapshots
|
|
74
|
+
WHERE billing_account_id = $1`, [billingAccountId]);
|
|
75
|
+
if (rows[0]?.latest_version !== activeVersion) {
|
|
76
|
+
throw conflict('active_snapshot_conflict', 'the billing account has unapplied entitlement history');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export async function readCurrentSubscriptionForUpdate(client, billingAccountId) {
|
|
80
|
+
const { rows } = await client.query(`SELECT subscription_id, revision_version
|
|
81
|
+
FROM billing_account_current_base_subscriptions
|
|
82
|
+
WHERE billing_account_id = $1
|
|
83
|
+
FOR UPDATE`, [billingAccountId]);
|
|
84
|
+
return rows[0];
|
|
85
|
+
}
|
|
86
|
+
export function validateCurrentSubscription(current, expected, previousSnapshot) {
|
|
87
|
+
if (expected === null) {
|
|
88
|
+
if (current !== undefined || previousSnapshot.schemaVersion !== 1) {
|
|
89
|
+
throw conflict('base_subscription_conflict', 'the billing account already has paid subscription state');
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (current === undefined ||
|
|
94
|
+
current.subscription_id !== expected.subscriptionId ||
|
|
95
|
+
current.revision_version !== expected.revisionVersion ||
|
|
96
|
+
previousSnapshot.schemaVersion !== 2 ||
|
|
97
|
+
previousSnapshot.sourceSubscriptionId !== expected.subscriptionId ||
|
|
98
|
+
previousSnapshot.sourceSubscriptionVersion !== expected.revisionVersion) {
|
|
99
|
+
throw conflict('base_subscription_conflict', 'the current base subscription changed; retry from the current billing account state');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export async function validateSubscriptionHistory(client, request, current) {
|
|
103
|
+
const base = await client.query(`SELECT billing_account_id
|
|
104
|
+
FROM billing_base_subscriptions
|
|
105
|
+
WHERE id = $1
|
|
106
|
+
FOR UPDATE`, [request.revision.subscriptionId]);
|
|
107
|
+
if (current === undefined) {
|
|
108
|
+
if (base.rows[0] !== undefined) {
|
|
109
|
+
throw conflict('base_subscription_conflict', 'the subscription id is already in use');
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (base.rows[0]?.billing_account_id !== request.billingAccountId) {
|
|
114
|
+
throw conflict('base_subscription_conflict', 'the current base subscription is incomplete');
|
|
115
|
+
}
|
|
116
|
+
const revisions = await client.query(`SELECT max(version)::integer AS latest_version
|
|
117
|
+
FROM billing_base_subscription_revisions
|
|
118
|
+
WHERE subscription_id = $1`, [request.revision.subscriptionId]);
|
|
119
|
+
if (revisions.rows[0]?.latest_version !== current.revision_version) {
|
|
120
|
+
throw conflict('base_subscription_conflict', 'the subscription has unapplied revision history');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export async function insertRevision(client, revision) {
|
|
124
|
+
await client.query(`INSERT INTO billing_base_subscription_revisions
|
|
125
|
+
(schema_version, subscription_id, billing_account_id, version, plan_version_id, state,
|
|
126
|
+
billing_interval, currency, base_amount_minor, current_period_start, current_period_end,
|
|
127
|
+
effective_from, effective_until, renews, content_checksum, verified_at, created_at)
|
|
128
|
+
VALUES
|
|
129
|
+
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)`, [
|
|
130
|
+
revision.schemaVersion,
|
|
131
|
+
revision.subscriptionId,
|
|
132
|
+
revision.billingAccountId,
|
|
133
|
+
revision.version,
|
|
134
|
+
revision.planVersionId,
|
|
135
|
+
revision.state,
|
|
136
|
+
revision.billingInterval,
|
|
137
|
+
revision.currency,
|
|
138
|
+
revision.baseAmountMinor,
|
|
139
|
+
revision.currentPeriodStart,
|
|
140
|
+
revision.currentPeriodEnd,
|
|
141
|
+
revision.effectiveFrom,
|
|
142
|
+
revision.effectiveUntil,
|
|
143
|
+
revision.renews,
|
|
144
|
+
revision.contentChecksum,
|
|
145
|
+
revision.verifiedAt,
|
|
146
|
+
revision.createdAt,
|
|
147
|
+
]);
|
|
148
|
+
}
|
|
149
|
+
export async function insertPaidSnapshot(client, snapshot) {
|
|
150
|
+
await client.query(`INSERT INTO billing_entitlement_snapshots
|
|
151
|
+
(id, billing_account_id, version, plan_version_id, schema_version, source_kind,
|
|
152
|
+
generation_reason, verification_status, effective_from, effective_until,
|
|
153
|
+
monthly_usage_anchor, entitlements, source_subscription_id, source_subscription_version,
|
|
154
|
+
content_checksum, verified_at, created_at)
|
|
155
|
+
VALUES
|
|
156
|
+
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12::jsonb, $13, $14, $15, $16, $17)`, [
|
|
157
|
+
snapshot.id,
|
|
158
|
+
snapshot.billingAccountId,
|
|
159
|
+
snapshot.version,
|
|
160
|
+
snapshot.planVersionId,
|
|
161
|
+
snapshot.schemaVersion,
|
|
162
|
+
snapshot.sourceKind,
|
|
163
|
+
snapshot.generationReason,
|
|
164
|
+
snapshot.verificationStatus,
|
|
165
|
+
snapshot.effectiveFrom,
|
|
166
|
+
snapshot.effectiveUntil,
|
|
167
|
+
snapshot.monthlyUsageAnchor,
|
|
168
|
+
JSON.stringify(snapshot.entitlements),
|
|
169
|
+
snapshot.sourceSubscriptionId,
|
|
170
|
+
snapshot.sourceSubscriptionVersion,
|
|
171
|
+
snapshot.contentChecksum,
|
|
172
|
+
snapshot.verifiedAt,
|
|
173
|
+
snapshot.createdAt,
|
|
174
|
+
]);
|
|
175
|
+
}
|
|
176
|
+
export async function compareAndSwapPointers(client, request, previousSnapshotId, current) {
|
|
177
|
+
const activeSnapshot = await client.query(`UPDATE billing_account_active_snapshots
|
|
178
|
+
SET snapshot_id = $3
|
|
179
|
+
WHERE billing_account_id = $1 AND snapshot_id = $2`, [request.billingAccountId, previousSnapshotId, request.snapshotId]);
|
|
180
|
+
if (activeSnapshot.rowCount !== 1) {
|
|
181
|
+
throw conflict('active_snapshot_conflict', 'the active entitlement snapshot changed');
|
|
182
|
+
}
|
|
183
|
+
if (current === undefined) {
|
|
184
|
+
const inserted = await client.query(`INSERT INTO billing_account_current_base_subscriptions
|
|
185
|
+
(billing_account_id, subscription_id, revision_version)
|
|
186
|
+
VALUES ($1, $2, $3)
|
|
187
|
+
ON CONFLICT (billing_account_id) DO NOTHING`, [request.billingAccountId, request.revision.subscriptionId, request.revision.version]);
|
|
188
|
+
if (inserted.rowCount !== 1) {
|
|
189
|
+
throw conflict('base_subscription_conflict', 'the current base subscription changed');
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const updated = await client.query(`UPDATE billing_account_current_base_subscriptions
|
|
194
|
+
SET revision_version = $4
|
|
195
|
+
WHERE billing_account_id = $1 AND subscription_id = $2 AND revision_version = $3`, [
|
|
196
|
+
request.billingAccountId,
|
|
197
|
+
current.subscription_id,
|
|
198
|
+
current.revision_version,
|
|
199
|
+
request.revision.version,
|
|
200
|
+
]);
|
|
201
|
+
if (updated.rowCount !== 1) {
|
|
202
|
+
throw conflict('base_subscription_conflict', 'the current base subscription changed');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
export async function insertOperation(client, input) {
|
|
206
|
+
await client.query(`INSERT INTO billing_subscription_reconciliation_operations
|
|
207
|
+
(operation_id, schema_version, action, billing_account_id, idempotency_key_hash,
|
|
208
|
+
request_fingerprint, subscription_id, revision_version, snapshot_id, result, created_at)
|
|
209
|
+
VALUES ($1, 1, 'paid_reconcile', $2, $3, $4, $5, $6, $7, $8::jsonb, $9)`, [
|
|
210
|
+
input.operationId,
|
|
211
|
+
input.result.billingAccountId,
|
|
212
|
+
input.idempotencyHash,
|
|
213
|
+
input.fingerprint,
|
|
214
|
+
input.result.subscriptionId,
|
|
215
|
+
input.result.subscriptionRevisionVersion,
|
|
216
|
+
input.result.snapshotId,
|
|
217
|
+
JSON.stringify(input.result),
|
|
218
|
+
input.createdAt,
|
|
219
|
+
]);
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=postgres-subscription-reconciliation-persistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-subscription-reconciliation-persistence.js","sourceRoot":"","sources":["../../src/billing/postgres-subscription-reconciliation-persistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PoolClient } from 'pg';
|
|
2
|
+
import { BillingSubscriptionReconciliationConflictError } from './subscription-reconciliation.js';
|
|
3
|
+
export declare function translateTransactionError(error: unknown): unknown;
|
|
4
|
+
export declare function conflict(code: ConstructorParameters<typeof BillingSubscriptionReconciliationConflictError>[0], message: string): BillingSubscriptionReconciliationConflictError;
|
|
5
|
+
export declare function keyGeneration(value: string): string;
|
|
6
|
+
export declare function timeout(name: string, value: number): number;
|
|
7
|
+
export declare function rollbackQuietly(client: PoolClient): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=postgres-subscription-reconciliation-support.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-subscription-reconciliation-support.d.ts","sourceRoot":"","sources":["../../src/billing/postgres-subscription-reconciliation-support.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,EAAE,8CAA8C,EAAE,MAAM,kCAAkC,CAAC;AAElG,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAgBjE;AAQD,wBAAgB,QAAQ,CACtB,IAAI,EAAE,qBAAqB,CAAC,OAAO,8CAA8C,CAAC,CAAC,CAAC,CAAC,EACrF,OAAO,EAAE,MAAM,kDAGhB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvE"}
|