@noodleseed/one 0.38.0 → 0.39.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.
Files changed (175) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +3 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/billing-apply-ops.d.ts +2 -0
  5. package/dist/commands/billing-apply-ops.d.ts.map +1 -0
  6. package/dist/commands/billing-apply-ops.js +224 -0
  7. package/dist/commands/billing-apply-ops.js.map +1 -0
  8. package/dist/commands/billing-migration-files.d.ts +13 -0
  9. package/dist/commands/billing-migration-files.d.ts.map +1 -0
  10. package/dist/commands/billing-migration-files.js +84 -0
  11. package/dist/commands/billing-migration-files.js.map +1 -0
  12. package/dist/commands/billing-ops.d.ts +3 -0
  13. package/dist/commands/billing-ops.d.ts.map +1 -0
  14. package/dist/commands/billing-ops.js +121 -0
  15. package/dist/commands/billing-ops.js.map +1 -0
  16. package/dist/commands/catalog-data-resources.d.ts.map +1 -1
  17. package/dist/commands/catalog-data-resources.js +19 -0
  18. package/dist/commands/catalog-data-resources.js.map +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/widget-scaffold-template.d.ts.map +1 -1
  23. package/dist/widget-scaffold-template.js +9 -0
  24. package/dist/widget-scaffold-template.js.map +1 -1
  25. package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.d.ts.map +1 -1
  26. package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js +4 -0
  27. package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js.map +1 -1
  28. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +3 -3
  29. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js.map +1 -1
  30. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.d.ts.map +1 -1
  31. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +1 -0
  32. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js.map +1 -1
  33. package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.d.ts.map +1 -1
  34. package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +28 -0
  35. package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js.map +1 -1
  36. package/node_modules/@noodle-borg/agent-kit/dist/skill-operations-refs.d.ts.map +1 -1
  37. package/node_modules/@noodle-borg/agent-kit/dist/skill-operations-refs.js +5 -0
  38. package/node_modules/@noodle-borg/agent-kit/dist/skill-operations-refs.js.map +1 -1
  39. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  40. package/node_modules/@noodle-borg/authoring/dist/assistant.d.ts +44 -0
  41. package/node_modules/@noodle-borg/authoring/dist/assistant.d.ts.map +1 -1
  42. package/node_modules/@noodle-borg/authoring/dist/assistant.js.map +1 -1
  43. package/node_modules/@noodle-borg/authoring/dist/index.d.ts +1 -1
  44. package/node_modules/@noodle-borg/authoring/dist/index.d.ts.map +1 -1
  45. package/node_modules/@noodle-borg/authoring/dist/index.js.map +1 -1
  46. package/node_modules/@noodle-borg/authoring/dist/server.js +6 -1
  47. package/node_modules/@noodle-borg/authoring/dist/server.js.map +1 -1
  48. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +83 -0
  49. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts.map +1 -1
  50. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +82 -14
  51. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js.map +1 -1
  52. package/node_modules/@noodle-borg/module-audit/dist/index.d.ts +2 -1
  53. package/node_modules/@noodle-borg/module-audit/dist/index.d.ts.map +1 -1
  54. package/node_modules/@noodle-borg/module-audit/dist/index.js +1 -1
  55. package/node_modules/@noodle-borg/module-audit/dist/index.js.map +1 -1
  56. package/node_modules/@noodle-borg/module-audit/dist/postgres-audit.d.ts +12 -3
  57. package/node_modules/@noodle-borg/module-audit/dist/postgres-audit.d.ts.map +1 -1
  58. package/node_modules/@noodle-borg/module-audit/dist/postgres-audit.js +30 -20
  59. package/node_modules/@noodle-borg/module-audit/dist/postgres-audit.js.map +1 -1
  60. package/node_modules/@noodle-borg/service/dist/billing/in-memory-serialization.d.ts +6 -0
  61. package/node_modules/@noodle-borg/service/dist/billing/in-memory-serialization.d.ts.map +1 -0
  62. package/node_modules/@noodle-borg/service/dist/billing/in-memory-serialization.js +23 -0
  63. package/node_modules/@noodle-borg/service/dist/billing/in-memory-serialization.js.map +1 -0
  64. package/node_modules/@noodle-borg/service/dist/billing/in-memory.d.ts +32 -0
  65. package/node_modules/@noodle-borg/service/dist/billing/in-memory.d.ts.map +1 -0
  66. package/node_modules/@noodle-borg/service/dist/billing/in-memory.js +185 -0
  67. package/node_modules/@noodle-borg/service/dist/billing/in-memory.js.map +1 -0
  68. package/node_modules/@noodle-borg/service/dist/billing/migration-apply.d.ts +98 -0
  69. package/node_modules/@noodle-borg/service/dist/billing/migration-apply.d.ts.map +1 -0
  70. package/node_modules/@noodle-borg/service/dist/billing/migration-apply.js +194 -0
  71. package/node_modules/@noodle-borg/service/dist/billing/migration-apply.js.map +1 -0
  72. package/node_modules/@noodle-borg/service/dist/billing/migration-contract.d.ts +79 -0
  73. package/node_modules/@noodle-borg/service/dist/billing/migration-contract.d.ts.map +1 -0
  74. package/node_modules/@noodle-borg/service/dist/billing/migration-contract.js +86 -0
  75. package/node_modules/@noodle-borg/service/dist/billing/migration-contract.js.map +1 -0
  76. package/node_modules/@noodle-borg/service/dist/billing/migration.d.ts +13 -0
  77. package/node_modules/@noodle-borg/service/dist/billing/migration.d.ts.map +1 -0
  78. package/node_modules/@noodle-borg/service/dist/billing/migration.js +246 -0
  79. package/node_modules/@noodle-borg/service/dist/billing/migration.js.map +1 -0
  80. package/node_modules/@noodle-borg/service/dist/billing/model.d.ts +85 -0
  81. package/node_modules/@noodle-borg/service/dist/billing/model.d.ts.map +1 -0
  82. package/node_modules/@noodle-borg/service/dist/billing/model.js +134 -0
  83. package/node_modules/@noodle-borg/service/dist/billing/model.js.map +1 -0
  84. package/node_modules/@noodle-borg/service/dist/billing/postgres-migration-support.d.ts +36 -0
  85. package/node_modules/@noodle-borg/service/dist/billing/postgres-migration-support.d.ts.map +1 -0
  86. package/node_modules/@noodle-borg/service/dist/billing/postgres-migration-support.js +122 -0
  87. package/node_modules/@noodle-borg/service/dist/billing/postgres-migration-support.js.map +1 -0
  88. package/node_modules/@noodle-borg/service/dist/billing/postgres-migration.d.ts +9 -0
  89. package/node_modules/@noodle-borg/service/dist/billing/postgres-migration.d.ts.map +1 -0
  90. package/node_modules/@noodle-borg/service/dist/billing/postgres-migration.js +265 -0
  91. package/node_modules/@noodle-borg/service/dist/billing/postgres-migration.js.map +1 -0
  92. package/node_modules/@noodle-borg/service/dist/billing/postgres-records.d.ts +66 -0
  93. package/node_modules/@noodle-borg/service/dist/billing/postgres-records.d.ts.map +1 -0
  94. package/node_modules/@noodle-borg/service/dist/billing/postgres-records.js +163 -0
  95. package/node_modules/@noodle-borg/service/dist/billing/postgres-records.js.map +1 -0
  96. package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.d.ts +4 -0
  97. package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.d.ts.map +1 -0
  98. package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js +211 -0
  99. package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js.map +1 -0
  100. package/node_modules/@noodle-borg/service/dist/billing/postgres.d.ts +33 -0
  101. package/node_modules/@noodle-borg/service/dist/billing/postgres.d.ts.map +1 -0
  102. package/node_modules/@noodle-borg/service/dist/billing/postgres.js +285 -0
  103. package/node_modules/@noodle-borg/service/dist/billing/postgres.js.map +1 -0
  104. package/node_modules/@noodle-borg/service/dist/billing/store.d.ts +27 -0
  105. package/node_modules/@noodle-borg/service/dist/billing/store.d.ts.map +1 -0
  106. package/node_modules/@noodle-borg/service/dist/billing/store.js +2 -0
  107. package/node_modules/@noodle-borg/service/dist/billing/store.js.map +1 -0
  108. package/node_modules/@noodle-borg/service/dist/index.d.ts +4 -0
  109. package/node_modules/@noodle-borg/service/dist/index.d.ts.map +1 -1
  110. package/node_modules/@noodle-borg/service/dist/index.js +3 -0
  111. package/node_modules/@noodle-borg/service/dist/index.js.map +1 -1
  112. package/node_modules/@noodle-borg/service/dist/modules/host.js +3 -0
  113. package/node_modules/@noodle-borg/service/dist/modules/host.js.map +1 -1
  114. package/node_modules/@noodle-borg/service/dist/options.d.ts +17 -5
  115. package/node_modules/@noodle-borg/service/dist/options.d.ts.map +1 -1
  116. package/node_modules/@noodle-borg/service/dist/routes/billing.d.ts +23 -0
  117. package/node_modules/@noodle-borg/service/dist/routes/billing.d.ts.map +1 -0
  118. package/node_modules/@noodle-borg/service/dist/routes/billing.js +165 -0
  119. package/node_modules/@noodle-borg/service/dist/routes/billing.js.map +1 -0
  120. package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.d.ts +28 -0
  121. package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.d.ts.map +1 -0
  122. package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.js +77 -0
  123. package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.js.map +1 -0
  124. package/node_modules/@noodle-borg/service/dist/routes/control-plane.d.ts.map +1 -1
  125. package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +17 -0
  126. package/node_modules/@noodle-borg/service/dist/routes/control-plane.js.map +1 -1
  127. package/node_modules/@noodle-borg/service/dist/serve.d.ts.map +1 -1
  128. package/node_modules/@noodle-borg/service/dist/serve.js +28 -6
  129. package/node_modules/@noodle-borg/service/dist/serve.js.map +1 -1
  130. package/node_modules/@noodle-borg/service/dist/service.d.ts.map +1 -1
  131. package/node_modules/@noodle-borg/service/dist/service.js +23 -30
  132. package/node_modules/@noodle-borg/service/dist/service.js.map +1 -1
  133. package/node_modules/@noodle-borg/service/dist/store/audit.d.ts +8 -0
  134. package/node_modules/@noodle-borg/service/dist/store/audit.d.ts.map +1 -1
  135. package/node_modules/@noodle-borg/service/dist/store/audit.js +15 -0
  136. package/node_modules/@noodle-borg/service/dist/store/audit.js.map +1 -1
  137. package/node_modules/@noodle-borg/service/dist/store/control-plane.d.ts +2 -1
  138. package/node_modules/@noodle-borg/service/dist/store/control-plane.d.ts.map +1 -1
  139. package/node_modules/@noodle-borg/service/dist/store/control-plane.js +81 -48
  140. package/node_modules/@noodle-borg/service/dist/store/control-plane.js.map +1 -1
  141. package/node_modules/@noodle-borg/service/dist/store/postgres-apps.d.ts +4 -2
  142. package/node_modules/@noodle-borg/service/dist/store/postgres-apps.d.ts.map +1 -1
  143. package/node_modules/@noodle-borg/service/dist/store/postgres-apps.js.map +1 -1
  144. package/node_modules/@noodle-borg/service/dist/store/postgres-billing.d.ts +11 -0
  145. package/node_modules/@noodle-borg/service/dist/store/postgres-billing.d.ts.map +1 -0
  146. package/node_modules/@noodle-borg/service/dist/store/postgres-billing.js +17 -0
  147. package/node_modules/@noodle-borg/service/dist/store/postgres-billing.js.map +1 -0
  148. package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.d.ts +1 -1
  149. package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.d.ts.map +1 -1
  150. package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.js +18 -6
  151. package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.js.map +1 -1
  152. package/node_modules/@noodle-borg/service/dist/store/postgres-schema.d.ts.map +1 -1
  153. package/node_modules/@noodle-borg/service/dist/store/postgres-schema.js +4 -0
  154. package/node_modules/@noodle-borg/service/dist/store/postgres-schema.js.map +1 -1
  155. package/node_modules/@noodle-borg/service/dist/store/postgres-signup.d.ts +14 -1
  156. package/node_modules/@noodle-borg/service/dist/store/postgres-signup.d.ts.map +1 -1
  157. package/node_modules/@noodle-borg/service/dist/store/postgres-signup.js +28 -0
  158. package/node_modules/@noodle-borg/service/dist/store/postgres-signup.js.map +1 -1
  159. package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts +2 -2
  160. package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts.map +1 -1
  161. package/node_modules/@noodle-borg/service/dist/store/postgres.js +9 -5
  162. package/node_modules/@noodle-borg/service/dist/store/postgres.js.map +1 -1
  163. package/node_modules/@noodle-borg/service/dist/store/validate.d.ts +4 -0
  164. package/node_modules/@noodle-borg/service/dist/store/validate.d.ts.map +1 -1
  165. package/node_modules/@noodle-borg/service/dist/store/validate.js +13 -0
  166. package/node_modules/@noodle-borg/service/dist/store/validate.js.map +1 -1
  167. package/node_modules/@noodle-borg/service/dist/store.d.ts +5 -2
  168. package/node_modules/@noodle-borg/service/dist/store.d.ts.map +1 -1
  169. package/node_modules/@noodle-borg/service/dist/store.js +1 -1
  170. package/node_modules/@noodle-borg/service/dist/store.js.map +1 -1
  171. package/node_modules/@noodle-borg/wire-contracts/dist/assistant.d.ts +3 -2
  172. package/node_modules/@noodle-borg/wire-contracts/dist/assistant.d.ts.map +1 -1
  173. package/node_modules/@noodle-borg/wire-contracts/dist/assistant.js +3 -2
  174. package/node_modules/@noodle-borg/wire-contracts/dist/assistant.js.map +1 -1
  175. package/package.json +1 -1
@@ -0,0 +1,265 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { insertAuditEvent } from '@noodle-borg/module-audit';
3
+ import { commercialPlanPolicyId } from '../commercial-plans.js';
4
+ import { legacyBillingMigrationMappingChecksum, previewLegacyBillingMigration, } from './migration.js';
5
+ import { LegacyBillingMigrationConflictError, legacyBillingMigrationPlanEvidenceChecksum, legacyBillingMigrationRequestFingerprint, legacyBillingMigrationSuccessAudit, normalizeBillingMigrationServiceUrl, parseLegacyBillingMigrationApplyRequest, } from './migration-apply.js';
6
+ import { GOOGLE_CONTROL_PLANE_ISSUER, normalizeBillingEmail, normalizeBillingIdentity, } from './model.js';
7
+ import { ensureDefaultBillingAccountForLegacyMigrationTx, ensureOrgBillingLinkTx, getActiveEntitlementSnapshotQuery, getBillingAccountQuery, getDefaultBillingAccountQuery, getOrgBillingLinkQuery, } from './postgres.js';
8
+ import { findPreparationById, findPreparationByIdempotencyKey, findPreparationByKind, LEGACY_BILLING_MIGRATION_KIND, preparationResult, previewOrganizationSlugs, transactionalLegacyMigrationControlPlane, transactionalLegacyMigrationInventory, } from './postgres-migration-support.js';
9
+ const TABLE_LOCKS = [
10
+ 'orgs',
11
+ 'org_members',
12
+ 'apps',
13
+ 'environments',
14
+ 'deploy_records',
15
+ 'policy_assignments',
16
+ 'billing_plan_versions',
17
+ 'billing_accounts',
18
+ 'billing_account_defaults',
19
+ 'billing_account_members',
20
+ 'billing_entitlement_snapshots',
21
+ 'billing_account_active_snapshots',
22
+ 'org_billing_home_accounts',
23
+ 'org_billing_links',
24
+ 'billing_legacy_migration_preparations',
25
+ 'billing_legacy_migration_accounts',
26
+ 'billing_legacy_migration_organizations',
27
+ 'billing_legacy_migration_apps',
28
+ 'billing_legacy_migration_plan_evidence',
29
+ ].join(', ');
30
+ export async function prepareLegacyBillingMigrationRow(pool, input, now) {
31
+ const request = parseLegacyBillingMigrationApplyRequest(input.request);
32
+ const service = normalizeBillingMigrationServiceUrl(input.service);
33
+ if (request.legacyPlanEvidence.service !== service) {
34
+ throw new LegacyBillingMigrationConflictError('legacy_plan_evidence_drift', 'legacy plan evidence targets a different service');
35
+ }
36
+ const actorIdentity = normalizeBillingIdentity({
37
+ identityIssuer: GOOGLE_CONTROL_PLANE_ISSUER,
38
+ subject: input.actor.subject,
39
+ });
40
+ const actor = {
41
+ subject: actorIdentity.subject,
42
+ email: normalizeBillingEmail(input.actor.email),
43
+ };
44
+ const mappingChecksum = legacyBillingMigrationMappingChecksum(request.mappings);
45
+ const planEvidenceChecksum = legacyBillingMigrationPlanEvidenceChecksum(request.legacyPlanEvidence);
46
+ const requestFingerprint = legacyBillingMigrationRequestFingerprint(request, actor, service);
47
+ const client = await pool.connect();
48
+ try {
49
+ // READ COMMITTED lets a waiter observe the predecessor's committed replay row after the
50
+ // transaction-scoped migration lock releases. EXCLUSIVE table locks freeze every source table
51
+ // before preview revalidation and wait behind in-flight SELECT ... FOR UPDATE writers. Migration
52
+ // intentionally takes no default-owner advisory locks: signup writes org tables before acquiring
53
+ // those locks, so mixing both lock orders here would create an inversion.
54
+ await client.query('BEGIN ISOLATION LEVEL READ COMMITTED');
55
+ await client.query('SELECT pg_advisory_xact_lock(hashtextextended($1, 0))', [
56
+ 'billing-legacy-shadow-prepare:v1',
57
+ ]);
58
+ const keyed = await findPreparationByIdempotencyKey(client, request.idempotencyKey);
59
+ if (keyed !== undefined) {
60
+ if (keyed.request_fingerprint !== requestFingerprint) {
61
+ throw new LegacyBillingMigrationConflictError('idempotency_key_conflict', 'idempotency key was already used by a different request or actor');
62
+ }
63
+ const replay = await preparationResult(client, keyed, true);
64
+ await insertAuditEvent(client, legacyBillingMigrationSuccessAudit(replay, actor), { now });
65
+ await client.query('COMMIT');
66
+ return replay;
67
+ }
68
+ const existing = await findPreparationByKind(client);
69
+ if (existing !== undefined) {
70
+ throw new LegacyBillingMigrationConflictError('migration_already_prepared', 'legacy billing migration was already prepared under a different idempotency key');
71
+ }
72
+ await client.query(`LOCK TABLE ${TABLE_LOCKS} IN EXCLUSIVE MODE`);
73
+ const preview = await previewLegacyBillingMigration(transactionalLegacyMigrationControlPlane(client), { schemaVersion: 1, mappings: request.mappings }, transactionalLegacyMigrationInventory(client));
74
+ if (!preview.ready) {
75
+ throw new LegacyBillingMigrationConflictError('preview_not_ready', 'legacy billing migration preview is no longer ready');
76
+ }
77
+ if (preview.previewChecksum !== request.expectedPreviewChecksum) {
78
+ throw new LegacyBillingMigrationConflictError('preview_checksum_mismatch', 'approved preview no longer matches current state');
79
+ }
80
+ await validateDefaultFreePlanEvidence(client, request, previewOrganizationSlugs(preview));
81
+ const preparedAt = now();
82
+ const migrationId = `bm_${randomUUID()}`;
83
+ await client.query(`INSERT INTO billing_legacy_migration_preparations
84
+ (id, migration_kind, schema_version, mode, state, idempotency_key,
85
+ request_fingerprint, mapping_checksum, preview_checksum, plan_evidence_checksum,
86
+ prepared_at, prepared_by_subject, prepared_by_email, reason)
87
+ VALUES ($1, $2, 1, 'shadow', 'prepared', $3, $4, $5, $6, $7, $8, $9, $10, $11)`, [
88
+ migrationId,
89
+ LEGACY_BILLING_MIGRATION_KIND,
90
+ request.idempotencyKey,
91
+ requestFingerprint,
92
+ mappingChecksum,
93
+ preview.previewChecksum,
94
+ planEvidenceChecksum,
95
+ preparedAt,
96
+ actor.subject,
97
+ actor.email,
98
+ request.reason,
99
+ ]);
100
+ const mappingByOrg = new Map(request.mappings.map((mapping) => [mapping.org, mapping]));
101
+ const unlinkedByOrg = new Map(preview.organizations.map((org) => [org.org, org]));
102
+ for (const fundingSet of preview.fundingSets) {
103
+ let billingAccountId;
104
+ let accountDisposition;
105
+ if (fundingSet.destination.kind === 'existing') {
106
+ billingAccountId = fundingSet.destination.billingAccountId;
107
+ accountDisposition = 'existing';
108
+ }
109
+ else {
110
+ const destination = fundingSet.destination;
111
+ const owner = preview.organizations.find((org) => org.mappedOwnerSubject === destination.subject);
112
+ const email = owner?.ownerCandidates.find((candidate) => candidate.subject === destination.subject)?.email;
113
+ if (email === undefined) {
114
+ throw new LegacyBillingMigrationConflictError('preview_not_ready', 'prepared funding destination no longer has a selected owner email');
115
+ }
116
+ const account = await ensureDefaultBillingAccountForLegacyMigrationTx(client, {
117
+ identityIssuer: destination.identityIssuer,
118
+ subject: destination.subject,
119
+ email,
120
+ }, preparedAt);
121
+ billingAccountId = account.id;
122
+ accountDisposition = 'created';
123
+ }
124
+ for (const org of fundingSet.organizations) {
125
+ const mapping = mappingByOrg.get(org);
126
+ if (mapping === undefined) {
127
+ throw new LegacyBillingMigrationConflictError('preview_not_ready', 'ready preview contains an organization without a mapping');
128
+ }
129
+ let link;
130
+ let disposition;
131
+ if (mapping.linkState === 'linked') {
132
+ link = await getOrgBillingLinkQuery(client, org);
133
+ disposition = 'preserved';
134
+ }
135
+ else {
136
+ const previewOrg = unlinkedByOrg.get(org);
137
+ const selected = previewOrg?.ownerCandidates.find((owner) => owner.subject === mapping.defaultBillingOwnerSubject);
138
+ if (selected === undefined) {
139
+ throw new LegacyBillingMigrationConflictError('preview_not_ready', 'mapped organization owner is no longer available');
140
+ }
141
+ link = await ensureOrgBillingLinkTx(client, {
142
+ org,
143
+ billingAccountId,
144
+ homeFreeBillingAccountId: billingAccountId,
145
+ homeOwner: {
146
+ identityIssuer: GOOGLE_CONTROL_PLANE_ISSUER,
147
+ subject: selected.subject,
148
+ },
149
+ linkedBy: actorIdentity,
150
+ reason: request.reason,
151
+ }, preparedAt);
152
+ disposition = 'created';
153
+ }
154
+ if (link === undefined || link.billingAccountId !== billingAccountId) {
155
+ throw new LegacyBillingMigrationConflictError('incomplete_billing_destination', 'organization billing link does not match its prepared funding destination');
156
+ }
157
+ await validateLinkedDefaultFreeTuple(client, link);
158
+ await client.query(`INSERT INTO billing_legacy_migration_organizations
159
+ (migration_id, org_slug, billing_account_id, link_disposition, link_version,
160
+ home_owner_identity_issuer, home_owner_subject)
161
+ VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
162
+ migrationId,
163
+ org,
164
+ billingAccountId,
165
+ disposition,
166
+ link.version,
167
+ link.homeOwner.identityIssuer,
168
+ link.homeOwner.subject,
169
+ ]);
170
+ }
171
+ const snapshot = await completeDefaultFreeSnapshot(client, billingAccountId);
172
+ const capacity = productionCapacity(snapshot.entitlements['apps.production.max']);
173
+ const grantCandidate = fundingSet.productionApps.length > capacity;
174
+ await client.query(`INSERT INTO billing_legacy_migration_accounts
175
+ (migration_id, billing_account_id, account_disposition, snapshot_id,
176
+ organization_count, production_app_count, production_capacity,
177
+ grant_candidate_at_preparation)
178
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, [
179
+ migrationId,
180
+ billingAccountId,
181
+ accountDisposition,
182
+ snapshot.id,
183
+ fundingSet.organizations.length,
184
+ fundingSet.productionApps.length,
185
+ capacity,
186
+ grantCandidate,
187
+ ]);
188
+ for (const app of fundingSet.productionApps) {
189
+ await client.query(`INSERT INTO billing_legacy_migration_apps
190
+ (migration_id, billing_account_id, org_slug, app_slug, app_created_at)
191
+ VALUES ($1, $2, $3, $4, $5)`, [migrationId, billingAccountId, app.org, app.app, app.createdAt]);
192
+ }
193
+ }
194
+ for (const projection of request.legacyPlanEvidence.projections) {
195
+ await client.query(`INSERT INTO billing_legacy_migration_plan_evidence
196
+ (migration_id, org_slug, source, plan_code, plan_state)
197
+ VALUES ($1, $2, 'default', 'free', 'active')`, [migrationId, projection.org]);
198
+ }
199
+ const stored = await findPreparationById(client, migrationId);
200
+ if (stored === undefined)
201
+ throw new Error('prepared billing migration record was not persisted');
202
+ const result = await preparationResult(client, stored, false);
203
+ await insertAuditEvent(client, legacyBillingMigrationSuccessAudit(result, actor), { now });
204
+ await client.query('COMMIT');
205
+ return result;
206
+ }
207
+ catch (error) {
208
+ await client.query('ROLLBACK').catch(() => undefined);
209
+ const code = postgresErrorCode(error);
210
+ if (code === '40001' || code === '40P01') {
211
+ throw new LegacyBillingMigrationConflictError('serialization_conflict', 'billing migration state changed concurrently; retry the exact request');
212
+ }
213
+ throw error;
214
+ }
215
+ finally {
216
+ client.release();
217
+ }
218
+ }
219
+ async function validateDefaultFreePlanEvidence(client, request, authoritativeOrganizations) {
220
+ const evidenceOrganizations = request.legacyPlanEvidence.projections
221
+ .map((projection) => projection.org)
222
+ .sort();
223
+ if (JSON.stringify(evidenceOrganizations) !== JSON.stringify([...authoritativeOrganizations].sort())) {
224
+ throw new LegacyBillingMigrationConflictError('legacy_plan_evidence_drift', 'legacy plan evidence does not cover every authoritative organization exactly once');
225
+ }
226
+ const policyIds = evidenceOrganizations.map(commercialPlanPolicyId);
227
+ const { rows } = await client.query('SELECT id FROM policy_assignments WHERE active = true AND id = ANY($1::text[]) LIMIT 1', [policyIds]);
228
+ if (rows[0] !== undefined) {
229
+ throw new LegacyBillingMigrationConflictError('legacy_plan_evidence_drift', 'a legacy plan projection is no longer default Free and active');
230
+ }
231
+ }
232
+ async function validateLinkedDefaultFreeTuple(client, link) {
233
+ if (link === undefined ||
234
+ link.billingAccountId !== link.homeFreeBillingAccountId ||
235
+ link.fallbackBillingAccountId !== link.homeFreeBillingAccountId) {
236
+ throw new LegacyBillingMigrationConflictError('incomplete_billing_destination', 'default-Free migration requires the active, home, and fallback accounts to match');
237
+ }
238
+ const ownerDefault = await getDefaultBillingAccountQuery(client, link.homeOwner, true);
239
+ const { rows } = await client.query(`SELECT role FROM billing_account_members
240
+ WHERE billing_account_id = $1 AND identity_issuer = $2 AND subject = $3`, [link.billingAccountId, link.homeOwner.identityIssuer, link.homeOwner.subject]);
241
+ if (ownerDefault?.id !== link.billingAccountId || rows[0]?.role !== 'owner') {
242
+ throw new LegacyBillingMigrationConflictError('incomplete_billing_destination', 'billing destination does not have a complete default owner tuple');
243
+ }
244
+ }
245
+ async function completeDefaultFreeSnapshot(client, billingAccountId) {
246
+ const account = await getBillingAccountQuery(client, billingAccountId);
247
+ const snapshot = await getActiveEntitlementSnapshotQuery(client, billingAccountId);
248
+ if (account?.state !== 'active' || snapshot?.planCode !== 'free') {
249
+ throw new LegacyBillingMigrationConflictError('incomplete_billing_destination', 'billing destination must have an active verified Free snapshot');
250
+ }
251
+ productionCapacity(snapshot.entitlements['apps.production.max']);
252
+ return snapshot;
253
+ }
254
+ function productionCapacity(value) {
255
+ if (!Number.isSafeInteger(value) || value < 0) {
256
+ throw new LegacyBillingMigrationConflictError('incomplete_billing_destination', 'billing destination has an invalid apps.production.max entitlement');
257
+ }
258
+ return value;
259
+ }
260
+ function postgresErrorCode(error) {
261
+ return typeof error === 'object' && error !== null && 'code' in error
262
+ ? String(error.code)
263
+ : undefined;
264
+ }
265
+ //# sourceMappingURL=postgres-migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-migration.js","sourceRoot":"","sources":["../../src/billing/postgres-migration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { type BillingAccountMemberRecord, type BillingAccountRecord, type EntitlementSnapshotRecord, type OrgBillingLinkRecord, type PlanVersionRecord } from './model.js';
2
+ export declare function accountRowToRecord(row: AccountRow): BillingAccountRecord;
3
+ export declare function memberRowToRecord(row: MemberRow): BillingAccountMemberRecord;
4
+ export declare function planVersionRowToRecord(row: PlanVersionRow): PlanVersionRecord;
5
+ export declare function entitlementSnapshotRowToRecord(row: EntitlementSnapshotRow): EntitlementSnapshotRecord;
6
+ export declare function orgBillingLinkRowToRecord(row: OrgBillingLinkRow): OrgBillingLinkRecord;
7
+ export declare function validateScalarId(name: string, value: string): string;
8
+ export interface AccountRow {
9
+ readonly id: string;
10
+ readonly display_name: string;
11
+ readonly state: string;
12
+ readonly created_at: Date | string;
13
+ }
14
+ export interface MemberRow {
15
+ readonly billing_account_id: string;
16
+ readonly identity_issuer: string;
17
+ readonly subject: string;
18
+ readonly email: string;
19
+ readonly role: string;
20
+ readonly created_at: Date | string;
21
+ }
22
+ export interface PlanVersionRow {
23
+ readonly id: string;
24
+ readonly plan_code: string;
25
+ readonly version: number;
26
+ readonly effective_from: Date | string;
27
+ readonly entitlements: unknown;
28
+ readonly content_checksum: string;
29
+ readonly created_at: Date | string;
30
+ }
31
+ export interface EntitlementSnapshotRow {
32
+ readonly id: string;
33
+ readonly billing_account_id: string;
34
+ readonly version: number;
35
+ readonly plan_version_id: string;
36
+ readonly plan_code: string;
37
+ readonly plan_version: number;
38
+ readonly plan_effective_from: Date | string;
39
+ readonly plan_entitlements: unknown;
40
+ readonly plan_content_checksum: string;
41
+ readonly plan_created_at: Date | string;
42
+ readonly source_kind: string;
43
+ readonly generation_reason: string;
44
+ readonly verification_status: string;
45
+ readonly effective_from: Date | string;
46
+ readonly monthly_usage_anchor: Date | string;
47
+ readonly entitlements: unknown;
48
+ readonly content_checksum: string;
49
+ readonly verified_at: Date | string;
50
+ readonly created_at: Date | string;
51
+ }
52
+ export interface OrgBillingLinkRow {
53
+ readonly org_slug: string;
54
+ readonly billing_account_id: string;
55
+ readonly home_free_billing_account_id: string;
56
+ readonly home_owner_identity_issuer: string;
57
+ readonly home_owner_subject: string;
58
+ readonly fallback_billing_account_id: string;
59
+ readonly version: number;
60
+ readonly active: boolean;
61
+ readonly linked_at: Date | string;
62
+ readonly linked_by_identity_issuer: string;
63
+ readonly linked_by_subject: string;
64
+ readonly reason: string;
65
+ }
66
+ //# sourceMappingURL=postgres-records.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-records.d.ts","sourceRoot":"","sources":["../../src/billing/postgres-records.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,163 @@
1
+ import { validateSlug } from '../store/validate.js';
2
+ import { billingContentChecksum, normalizeBillingEmail, normalizeBillingIdentity, validateBillingAccountId, } from './model.js';
3
+ export function accountRowToRecord(row) {
4
+ if (row.state !== 'active' && row.state !== 'draft' && row.state !== 'inactive') {
5
+ throw new Error('persisted billing account has an invalid state');
6
+ }
7
+ return {
8
+ id: validateBillingAccountId(row.id),
9
+ displayName: row.display_name,
10
+ state: row.state,
11
+ createdAt: toIsoString(row.created_at),
12
+ };
13
+ }
14
+ export function memberRowToRecord(row) {
15
+ if (row.role !== 'owner' && row.role !== 'admin' && row.role !== 'viewer') {
16
+ throw new Error('persisted billing member has an invalid role');
17
+ }
18
+ return {
19
+ billingAccountId: validateBillingAccountId(row.billing_account_id),
20
+ ...normalizeBillingIdentity({
21
+ identityIssuer: row.identity_issuer,
22
+ subject: row.subject,
23
+ }),
24
+ email: normalizeBillingEmail(row.email),
25
+ role: row.role,
26
+ createdAt: toIsoString(row.created_at),
27
+ };
28
+ }
29
+ export function planVersionRowToRecord(row) {
30
+ const effectiveFrom = toIsoString(row.effective_from);
31
+ const entitlements = parseEntitlements(row.entitlements);
32
+ const record = {
33
+ id: validateScalarId('plan version id', row.id),
34
+ planCode: validateScalarId('plan code', row.plan_code),
35
+ version: validatePositiveInteger('plan version', row.version),
36
+ effectiveFrom,
37
+ entitlements,
38
+ contentChecksum: row.content_checksum,
39
+ createdAt: toIsoString(row.created_at),
40
+ };
41
+ const checksum = billingContentChecksum({
42
+ id: record.id,
43
+ planCode: record.planCode,
44
+ version: record.version,
45
+ effectiveFrom: record.effectiveFrom,
46
+ entitlements: record.entitlements,
47
+ });
48
+ if (checksum !== record.contentChecksum) {
49
+ throw new Error(`persisted plan version ${record.id} failed checksum verification`);
50
+ }
51
+ return record;
52
+ }
53
+ export function entitlementSnapshotRowToRecord(row) {
54
+ if (row.source_kind !== 'system-free' ||
55
+ row.generation_reason !== 'default-account-created' ||
56
+ row.verification_status !== 'verified') {
57
+ throw new Error('persisted entitlement snapshot has an unsupported provenance');
58
+ }
59
+ const effectiveFrom = toIsoString(row.effective_from);
60
+ const monthlyUsageAnchor = toIsoString(row.monthly_usage_anchor);
61
+ const entitlements = parseEntitlements(row.entitlements);
62
+ const plan = planVersionRowToRecord({
63
+ id: row.plan_version_id,
64
+ plan_code: row.plan_code,
65
+ version: row.plan_version,
66
+ effective_from: row.plan_effective_from,
67
+ entitlements: row.plan_entitlements,
68
+ content_checksum: row.plan_content_checksum,
69
+ created_at: row.plan_created_at,
70
+ });
71
+ const record = {
72
+ id: validateScalarId('entitlement snapshot id', row.id),
73
+ billingAccountId: validateBillingAccountId(row.billing_account_id),
74
+ version: validatePositiveInteger('entitlement snapshot version', row.version),
75
+ planVersionId: validateScalarId('plan version id', row.plan_version_id),
76
+ planCode: plan.planCode,
77
+ planVersion: plan.version,
78
+ sourceKind: row.source_kind,
79
+ generationReason: row.generation_reason,
80
+ verificationStatus: row.verification_status,
81
+ effectiveFrom,
82
+ monthlyUsageAnchor,
83
+ entitlements,
84
+ contentChecksum: row.content_checksum,
85
+ verifiedAt: toIsoString(row.verified_at),
86
+ createdAt: toIsoString(row.created_at),
87
+ };
88
+ const checksum = billingContentChecksum({
89
+ billingAccountId: record.billingAccountId,
90
+ version: record.version,
91
+ planVersionId: record.planVersionId,
92
+ effectiveFrom: record.effectiveFrom,
93
+ monthlyUsageAnchor: record.monthlyUsageAnchor,
94
+ entitlements: record.entitlements,
95
+ });
96
+ if (checksum !== record.contentChecksum) {
97
+ throw new Error(`persisted entitlement snapshot ${record.id} failed checksum verification`);
98
+ }
99
+ return record;
100
+ }
101
+ export function orgBillingLinkRowToRecord(row) {
102
+ if (!row.active)
103
+ throw new Error('persisted current billing-account link is inactive');
104
+ return {
105
+ orgSlug: validateSlug('org', row.org_slug),
106
+ billingAccountId: validateBillingAccountId(row.billing_account_id),
107
+ homeFreeBillingAccountId: validateBillingAccountId(row.home_free_billing_account_id),
108
+ homeOwner: normalizeBillingIdentity({
109
+ identityIssuer: row.home_owner_identity_issuer,
110
+ subject: row.home_owner_subject,
111
+ }),
112
+ fallbackBillingAccountId: validateBillingAccountId(row.fallback_billing_account_id),
113
+ version: validatePositiveInteger('billing link version', row.version),
114
+ active: true,
115
+ linkedAt: toIsoString(row.linked_at),
116
+ linkedBy: normalizeBillingIdentity({
117
+ identityIssuer: row.linked_by_identity_issuer,
118
+ subject: row.linked_by_subject,
119
+ }),
120
+ reason: validateScalarId('billing link reason', row.reason),
121
+ };
122
+ }
123
+ function parseEntitlements(value) {
124
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
125
+ throw new Error('persisted entitlements must be an object');
126
+ }
127
+ const entitlements = {};
128
+ for (const [key, candidate] of Object.entries(value)) {
129
+ validateScalarId('entitlement key', key);
130
+ if (candidate !== null &&
131
+ typeof candidate !== 'boolean' &&
132
+ typeof candidate !== 'string' &&
133
+ (typeof candidate !== 'number' || !Number.isFinite(candidate))) {
134
+ throw new Error(`persisted entitlement ${key} has an invalid value`);
135
+ }
136
+ entitlements[key] = candidate;
137
+ }
138
+ return Object.freeze(entitlements);
139
+ }
140
+ function validatePositiveInteger(name, value) {
141
+ if (!Number.isSafeInteger(value) || value < 1)
142
+ throw new Error(`${name} must be positive`);
143
+ return value;
144
+ }
145
+ export function validateScalarId(name, value) {
146
+ const normalized = value.trim();
147
+ if (normalized.length === 0 ||
148
+ normalized.length > 512 ||
149
+ [...normalized].some((character) => {
150
+ const code = character.charCodeAt(0);
151
+ return code <= 0x1f || code === 0x7f;
152
+ })) {
153
+ throw new Error(`${name} must be a non-empty scalar identifier`);
154
+ }
155
+ return normalized;
156
+ }
157
+ function toIsoString(value) {
158
+ const date = value instanceof Date ? value : new Date(value);
159
+ if (!Number.isFinite(date.getTime()))
160
+ throw new Error('persisted billing timestamp is invalid');
161
+ return date.toISOString();
162
+ }
163
+ //# sourceMappingURL=postgres-records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-records.js","sourceRoot":"","sources":["../../src/billing/postgres-records.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Pool } from 'pg';
2
+ /** Additive BA-1 schema. No existing organization is linked or otherwise migrated here. */
3
+ export declare function ensureBillingSchema(pool: Pool): Promise<void>;
4
+ //# sourceMappingURL=postgres-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-schema.d.ts","sourceRoot":"","sources":["../../src/billing/postgres-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAI/B,2FAA2F;AAC3F,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAuNnE"}