@noodleseed/one 0.48.0 → 0.49.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 (229) hide show
  1. package/dist/commands/archive-ops.js +1 -1
  2. package/dist/commands/archive-ops.js.map +1 -1
  3. package/dist/commands/billing-admission-output.d.ts +16 -0
  4. package/dist/commands/billing-admission-output.d.ts.map +1 -0
  5. package/dist/commands/billing-admission-output.js +40 -0
  6. package/dist/commands/billing-admission-output.js.map +1 -0
  7. package/dist/commands/billing-enforcement-activation-args.d.ts +40 -0
  8. package/dist/commands/billing-enforcement-activation-args.d.ts.map +1 -0
  9. package/dist/commands/billing-enforcement-activation-args.js +125 -0
  10. package/dist/commands/billing-enforcement-activation-args.js.map +1 -0
  11. package/dist/commands/billing-enforcement-activation-files.d.ts +11 -0
  12. package/dist/commands/billing-enforcement-activation-files.d.ts.map +1 -0
  13. package/dist/commands/billing-enforcement-activation-files.js +54 -0
  14. package/dist/commands/billing-enforcement-activation-files.js.map +1 -0
  15. package/dist/commands/billing-enforcement-activation-ops.d.ts +2 -0
  16. package/dist/commands/billing-enforcement-activation-ops.d.ts.map +1 -0
  17. package/dist/commands/billing-enforcement-activation-ops.js +283 -0
  18. package/dist/commands/billing-enforcement-activation-ops.js.map +1 -0
  19. package/dist/commands/billing-enforcement-ops.d.ts.map +1 -1
  20. package/dist/commands/billing-enforcement-ops.js +5 -1
  21. package/dist/commands/billing-enforcement-ops.js.map +1 -1
  22. package/dist/commands/billing-read-ops.d.ts.map +1 -1
  23. package/dist/commands/billing-read-ops.js +15 -3
  24. package/dist/commands/billing-read-ops.js.map +1 -1
  25. package/dist/commands/billing-read-view.d.ts +40 -1
  26. package/dist/commands/billing-read-view.d.ts.map +1 -1
  27. package/dist/commands/billing-read-view.js +50 -0
  28. package/dist/commands/billing-read-view.js.map +1 -1
  29. package/dist/commands/catalog-data-resources.d.ts.map +1 -1
  30. package/dist/commands/catalog-data-resources.js +4 -3
  31. package/dist/commands/catalog-data-resources.js.map +1 -1
  32. package/dist/commands/deploy-ops.d.ts +1 -0
  33. package/dist/commands/deploy-ops.d.ts.map +1 -1
  34. package/dist/commands/deploy-ops.js +5 -0
  35. package/dist/commands/deploy-ops.js.map +1 -1
  36. package/dist/commands/deploy-status-ops.js +1 -1
  37. package/dist/commands/deploy-status-ops.js.map +1 -1
  38. package/dist/commands/shared.d.ts.map +1 -1
  39. package/dist/commands/shared.js +13 -0
  40. package/dist/commands/shared.js.map +1 -1
  41. package/dist/deploy.d.ts +1 -0
  42. package/dist/deploy.d.ts.map +1 -1
  43. package/dist/deploy.js +1 -0
  44. package/dist/deploy.js.map +1 -1
  45. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  46. package/node_modules/@noodle-borg/protocol/dist/mapping.d.ts.map +1 -1
  47. package/node_modules/@noodle-borg/protocol/dist/mapping.js +2 -0
  48. package/node_modules/@noodle-borg/protocol/dist/mapping.js.map +1 -1
  49. package/node_modules/@noodle-borg/runtime/dist/result.d.ts +3 -1
  50. package/node_modules/@noodle-borg/runtime/dist/result.d.ts.map +1 -1
  51. package/node_modules/@noodle-borg/runtime/dist/result.js.map +1 -1
  52. package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.d.ts +10 -0
  53. package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.d.ts.map +1 -1
  54. package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.js +26 -1
  55. package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.js.map +1 -1
  56. package/node_modules/@noodle-borg/service/dist/billing/authoritative-admission.d.ts +46 -0
  57. package/node_modules/@noodle-borg/service/dist/billing/authoritative-admission.d.ts.map +1 -0
  58. package/node_modules/@noodle-borg/service/dist/billing/authoritative-admission.js +111 -0
  59. package/node_modules/@noodle-borg/service/dist/billing/authoritative-admission.js.map +1 -0
  60. package/node_modules/@noodle-borg/service/dist/billing/commercial-enforcement-projection.d.ts +80 -0
  61. package/node_modules/@noodle-borg/service/dist/billing/commercial-enforcement-projection.d.ts.map +1 -0
  62. package/node_modules/@noodle-borg/service/dist/billing/commercial-enforcement-projection.js +2 -0
  63. package/node_modules/@noodle-borg/service/dist/billing/commercial-enforcement-projection.js.map +1 -0
  64. package/node_modules/@noodle-borg/service/dist/billing/commercial-entitlements.d.ts +18 -0
  65. package/node_modules/@noodle-borg/service/dist/billing/commercial-entitlements.d.ts.map +1 -0
  66. package/node_modules/@noodle-borg/service/dist/billing/commercial-entitlements.js +51 -0
  67. package/node_modules/@noodle-borg/service/dist/billing/commercial-entitlements.js.map +1 -0
  68. package/node_modules/@noodle-borg/service/dist/billing/enforcement-activation-support.d.ts +34 -0
  69. package/node_modules/@noodle-borg/service/dist/billing/enforcement-activation-support.d.ts.map +1 -0
  70. package/node_modules/@noodle-borg/service/dist/billing/enforcement-activation-support.js +125 -0
  71. package/node_modules/@noodle-borg/service/dist/billing/enforcement-activation-support.js.map +1 -0
  72. package/node_modules/@noodle-borg/service/dist/billing/enforcement-activation.d.ts +265 -0
  73. package/node_modules/@noodle-borg/service/dist/billing/enforcement-activation.d.ts.map +1 -0
  74. package/node_modules/@noodle-borg/service/dist/billing/enforcement-activation.js +340 -0
  75. package/node_modules/@noodle-borg/service/dist/billing/enforcement-activation.js.map +1 -0
  76. package/node_modules/@noodle-borg/service/dist/billing/enforcement-profile.d.ts +1 -1
  77. package/node_modules/@noodle-borg/service/dist/billing/integration.d.ts +15 -3
  78. package/node_modules/@noodle-borg/service/dist/billing/integration.d.ts.map +1 -1
  79. package/node_modules/@noodle-borg/service/dist/billing/integration.js +56 -3
  80. package/node_modules/@noodle-borg/service/dist/billing/integration.js.map +1 -1
  81. package/node_modules/@noodle-borg/service/dist/billing/postgres-authoritative-authority.d.ts +20 -0
  82. package/node_modules/@noodle-borg/service/dist/billing/postgres-authoritative-authority.d.ts.map +1 -0
  83. package/node_modules/@noodle-borg/service/dist/billing/postgres-authoritative-authority.js +121 -0
  84. package/node_modules/@noodle-borg/service/dist/billing/postgres-authoritative-authority.js.map +1 -0
  85. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-apps.d.ts +10 -0
  86. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-apps.d.ts.map +1 -0
  87. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-apps.js +33 -0
  88. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-apps.js.map +1 -0
  89. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-counters.d.ts +25 -0
  90. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-counters.d.ts.map +1 -0
  91. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-counters.js +248 -0
  92. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-counters.js.map +1 -0
  93. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-projection.d.ts +17 -0
  94. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-projection.d.ts.map +1 -0
  95. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-projection.js +278 -0
  96. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-projection.js.map +1 -0
  97. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-transaction.d.ts +7 -0
  98. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-transaction.d.ts.map +1 -0
  99. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-transaction.js +63 -0
  100. package/node_modules/@noodle-borg/service/dist/billing/postgres-commercial-enforcement-transaction.js.map +1 -0
  101. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-locks.d.ts +6 -0
  102. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-locks.d.ts.map +1 -0
  103. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-locks.js +89 -0
  104. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-locks.js.map +1 -0
  105. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-preflight.d.ts +13 -0
  106. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-preflight.d.ts.map +1 -0
  107. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-preflight.js +193 -0
  108. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-preflight.js.map +1 -0
  109. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-schema.d.ts +4 -0
  110. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-schema.d.ts.map +1 -0
  111. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-schema.js +119 -0
  112. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-schema.js.map +1 -0
  113. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-support.d.ts +65 -0
  114. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-support.d.ts.map +1 -0
  115. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-support.js +159 -0
  116. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation-support.js.map +1 -0
  117. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation.d.ts +31 -0
  118. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation.d.ts.map +1 -0
  119. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation.js +247 -0
  120. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-activation.js.map +1 -0
  121. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-profile-schema.d.ts.map +1 -1
  122. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-profile-schema.js +40 -0
  123. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-profile-schema.js.map +1 -1
  124. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-profile.d.ts +1 -0
  125. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-profile.d.ts.map +1 -1
  126. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-profile.js +45 -22
  127. package/node_modules/@noodle-borg/service/dist/billing/postgres-enforcement-profile.js.map +1 -1
  128. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission-ledger.d.ts +33 -0
  129. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission-ledger.d.ts.map +1 -0
  130. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission-ledger.js +158 -0
  131. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission-ledger.js.map +1 -0
  132. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission.d.ts +18 -0
  133. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission.d.ts.map +1 -0
  134. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission.js +326 -0
  135. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-admission.js.map +1 -0
  136. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-epochs.d.ts +2 -0
  137. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-epochs.d.ts.map +1 -1
  138. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-epochs.js +10 -5
  139. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-epochs.js.map +1 -1
  140. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-live-validation.js +3 -3
  141. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-live-validation.js.map +1 -1
  142. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-readiness.d.ts +3 -1
  143. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-readiness.d.ts.map +1 -1
  144. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-readiness.js +8 -2
  145. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-readiness.js.map +1 -1
  146. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-reconciliation.js +4 -4
  147. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-reconciliation.js.map +1 -1
  148. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-runtime.d.ts +2 -2
  149. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-runtime.d.ts.map +1 -1
  150. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-runtime.js.map +1 -1
  151. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-scheduler-store.js +1 -1
  152. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-schema.d.ts.map +1 -1
  153. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-schema.js +27 -1
  154. package/node_modules/@noodle-borg/service/dist/billing/postgres-meter-schema.js.map +1 -1
  155. package/node_modules/@noodle-borg/service/dist/billing/postgres-production-app-admission.d.ts +33 -0
  156. package/node_modules/@noodle-borg/service/dist/billing/postgres-production-app-admission.d.ts.map +1 -0
  157. package/node_modules/@noodle-borg/service/dist/billing/postgres-production-app-admission.js +272 -0
  158. package/node_modules/@noodle-borg/service/dist/billing/postgres-production-app-admission.js.map +1 -0
  159. package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.d.ts.map +1 -1
  160. package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js +2 -0
  161. package/node_modules/@noodle-borg/service/dist/billing/postgres-schema.js.map +1 -1
  162. package/node_modules/@noodle-borg/service/dist/billing/read-contract.d.ts +174 -28
  163. package/node_modules/@noodle-borg/service/dist/billing/read-contract.d.ts.map +1 -1
  164. package/node_modules/@noodle-borg/service/dist/billing/read-contract.js +51 -6
  165. package/node_modules/@noodle-borg/service/dist/billing/read-contract.js.map +1 -1
  166. package/node_modules/@noodle-borg/service/dist/billing-public.d.ts +3 -0
  167. package/node_modules/@noodle-borg/service/dist/billing-public.d.ts.map +1 -1
  168. package/node_modules/@noodle-borg/service/dist/billing-public.js +3 -0
  169. package/node_modules/@noodle-borg/service/dist/billing-public.js.map +1 -1
  170. package/node_modules/@noodle-borg/service/dist/options.d.ts +14 -2
  171. package/node_modules/@noodle-borg/service/dist/options.d.ts.map +1 -1
  172. package/node_modules/@noodle-borg/service/dist/persistence-options.d.ts.map +1 -1
  173. package/node_modules/@noodle-borg/service/dist/persistence-options.js +9 -0
  174. package/node_modules/@noodle-borg/service/dist/persistence-options.js.map +1 -1
  175. package/node_modules/@noodle-borg/service/dist/registry.d.ts +2 -0
  176. package/node_modules/@noodle-borg/service/dist/registry.d.ts.map +1 -1
  177. package/node_modules/@noodle-borg/service/dist/registry.js +10 -0
  178. package/node_modules/@noodle-borg/service/dist/registry.js.map +1 -1
  179. package/node_modules/@noodle-borg/service/dist/routes/archive.d.ts.map +1 -1
  180. package/node_modules/@noodle-borg/service/dist/routes/archive.js +18 -1
  181. package/node_modules/@noodle-borg/service/dist/routes/archive.js.map +1 -1
  182. package/node_modules/@noodle-borg/service/dist/routes/billing-enforcement-activation.d.ts +15 -0
  183. package/node_modules/@noodle-borg/service/dist/routes/billing-enforcement-activation.d.ts.map +1 -0
  184. package/node_modules/@noodle-borg/service/dist/routes/billing-enforcement-activation.js +197 -0
  185. package/node_modules/@noodle-borg/service/dist/routes/billing-enforcement-activation.js.map +1 -0
  186. package/node_modules/@noodle-borg/service/dist/routes/billing-production-app-response.d.ts +15 -0
  187. package/node_modules/@noodle-borg/service/dist/routes/billing-production-app-response.d.ts.map +1 -0
  188. package/node_modules/@noodle-borg/service/dist/routes/billing-production-app-response.js +33 -0
  189. package/node_modules/@noodle-borg/service/dist/routes/billing-production-app-response.js.map +1 -0
  190. package/node_modules/@noodle-borg/service/dist/routes/billing-read.d.ts +2 -0
  191. package/node_modules/@noodle-borg/service/dist/routes/billing-read.d.ts.map +1 -1
  192. package/node_modules/@noodle-borg/service/dist/routes/billing-read.js +203 -41
  193. package/node_modules/@noodle-borg/service/dist/routes/billing-read.js.map +1 -1
  194. package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.d.ts +4 -0
  195. package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.d.ts.map +1 -1
  196. package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.js +25 -0
  197. package/node_modules/@noodle-borg/service/dist/routes/commercial-dispatch.js.map +1 -1
  198. package/node_modules/@noodle-borg/service/dist/routes/commercial-service-deps.d.ts +1 -0
  199. package/node_modules/@noodle-borg/service/dist/routes/commercial-service-deps.d.ts.map +1 -1
  200. package/node_modules/@noodle-borg/service/dist/routes/commercial-service-deps.js +9 -1
  201. package/node_modules/@noodle-borg/service/dist/routes/commercial-service-deps.js.map +1 -1
  202. package/node_modules/@noodle-borg/service/dist/routes/control-plane.d.ts.map +1 -1
  203. package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +19 -1
  204. package/node_modules/@noodle-borg/service/dist/routes/control-plane.js.map +1 -1
  205. package/node_modules/@noodle-borg/service/dist/routes/rollback.d.ts.map +1 -1
  206. package/node_modules/@noodle-borg/service/dist/routes/rollback.js +19 -1
  207. package/node_modules/@noodle-borg/service/dist/routes/rollback.js.map +1 -1
  208. package/node_modules/@noodle-borg/service/dist/serve.d.ts.map +1 -1
  209. package/node_modules/@noodle-borg/service/dist/serve.js +41 -1
  210. package/node_modules/@noodle-borg/service/dist/serve.js.map +1 -1
  211. package/node_modules/@noodle-borg/service/dist/service.d.ts.map +1 -1
  212. package/node_modules/@noodle-borg/service/dist/service.js +6 -3
  213. package/node_modules/@noodle-borg/service/dist/service.js.map +1 -1
  214. package/node_modules/@noodle-borg/service/dist/store/cloudsql-pool.js +3 -3
  215. package/node_modules/@noodle-borg/service/dist/store/cloudsql-pool.js.map +1 -1
  216. package/node_modules/@noodle-borg/service/dist/store/postgres-apps.d.ts +5 -7
  217. package/node_modules/@noodle-borg/service/dist/store/postgres-apps.d.ts.map +1 -1
  218. package/node_modules/@noodle-borg/service/dist/store/postgres-apps.js +71 -0
  219. package/node_modules/@noodle-borg/service/dist/store/postgres-apps.js.map +1 -1
  220. package/node_modules/@noodle-borg/service/dist/store/postgres-github-runs.d.ts.map +1 -1
  221. package/node_modules/@noodle-borg/service/dist/store/postgres-github-runs.js +7 -0
  222. package/node_modules/@noodle-borg/service/dist/store/postgres-github-runs.js.map +1 -1
  223. package/node_modules/@noodle-borg/service/dist/store/postgres-schema.d.ts.map +1 -1
  224. package/node_modules/@noodle-borg/service/dist/store/postgres-schema.js +5 -0
  225. package/node_modules/@noodle-borg/service/dist/store/postgres-schema.js.map +1 -1
  226. package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts.map +1 -1
  227. package/node_modules/@noodle-borg/service/dist/store/postgres.js +29 -34
  228. package/node_modules/@noodle-borg/service/dist/store/postgres.js.map +1 -1
  229. package/package.json +1 -1
@@ -0,0 +1,193 @@
1
+ import { isBillingCommercialFreeV1Entitlements, parseBillingCommercialUsageEntitlements, } from './commercial-entitlements.js';
2
+ import { BILLING_AUTHORITATIVE_ADMISSION_CONTRACT_VERSION, buildBillingEnforcementActivationPreview, normalizeActivationServiceUrl, } from './enforcement-activation.js';
3
+ import { billingContentChecksum } from './model.js';
4
+ import { requireActivationState, stateRowToStatus, validateAdmissionContractVersion, validateReleaseSha, } from './postgres-enforcement-activation-support.js';
5
+ import { readEnforcementCohortStatusTx } from './postgres-enforcement-profile.js';
6
+ import { readBillingMeterTransactionTime } from './postgres-meter-clock.js';
7
+ export function createPostgresBillingEnforcementActivationPreflight(options) {
8
+ const resolved = resolveOptions(options);
9
+ return async ({ client, approval, checkedAt }) => {
10
+ const transactionTime = await readBillingMeterTransactionTime(client);
11
+ if (transactionTime !== checkedAt) {
12
+ throw new Error('billing enforcement preflight must use the activation transaction clock');
13
+ }
14
+ const signals = await readPostgresBillingEnforcementActivationSignalsTx(client, checkedAt, resolved);
15
+ return buildBillingEnforcementActivationPreview({ approval, checkedAt, signals });
16
+ };
17
+ }
18
+ export async function readPostgresBillingEnforcementActivationSignalsTx(client, checkedAt, options) {
19
+ const resolved = resolveOptions(options);
20
+ const cohort = await readEnforcementCohortStatusTx(client);
21
+ const activation = stateRowToStatus(await requireActivationState(client, false));
22
+ const epochResult = await client.query(`
23
+ SELECT id, purpose, state, release_sha, admission_contract_version
24
+ FROM billing_meter_epochs
25
+ WHERE state IN ('prepared', 'active')
26
+ ORDER BY state, purpose, id
27
+ `);
28
+ const capacity = await readCapacitySignals(client);
29
+ const readiness = resolved.meterReadiness === undefined
30
+ ? undefined
31
+ : await resolved.meterReadiness.readMeterReadinessTx(client, checkedAt);
32
+ const prepared = epochResult.rows.filter((row) => row.state === 'prepared');
33
+ const active = epochResult.rows.filter((row) => row.state === 'active');
34
+ const validationEpoch = prepared.length === 1 && prepared[0]?.purpose === 'validation' ? prepared[0] : undefined;
35
+ return {
36
+ cohortState: cohort.state,
37
+ cohortSealId: cohort.sealId,
38
+ billingAttributionComplete: cohort.billingAttributionComplete,
39
+ unprofiledAccountCount: cohort.unprofiledAccountCount,
40
+ activationState: activation.state,
41
+ activationGeneration: activation.generation,
42
+ activeEpochId: active[0]?.id ?? activation.activeEpochId,
43
+ preparedValidationEpochId: validationEpoch?.id ?? null,
44
+ preparedValidationEpochReleaseSha: validationEpoch?.release_sha ?? null,
45
+ preparedValidationEpochAdmissionContractVersion: validationEpoch?.admission_contract_version ?? null,
46
+ currentServiceOrigin: resolved.serviceOrigin,
47
+ currentServiceReleaseSha: resolved.currentReleaseSha,
48
+ supportedAdmissionContractVersion: resolved.supportedAdmissionContractVersion,
49
+ technicalReadiness: readiness?.technicalReadiness ?? 'unavailable',
50
+ invalidEnforcedEntitlementAccountCount: capacity.invalidEnforcedEntitlementAccountCount,
51
+ nonFreeEnforcedAccountCount: capacity.nonFreeEnforcedAccountCount,
52
+ enforcedOverCapacityAccountCount: capacity.enforcedOverCapacityAccountCount,
53
+ legacyInternalExemptOverCapacityAccountCount: capacity.legacyInternalExemptOverCapacityAccountCount,
54
+ };
55
+ }
56
+ async function readCapacitySignals(client) {
57
+ const { rows } = await client.query(`
58
+ SELECT account.id AS account_id, account.state AS account_state,
59
+ profile.mode, profile.source AS profile_source,
60
+ profile.cohort_seal_id AS profile_cohort_seal_id,
61
+ profile.effective_from AS profile_effective_from,
62
+ seal.id AS cohort_seal_id, seal.sealed_at AS cohort_sealed_at,
63
+ snapshot.id AS snapshot_id, snapshot.version AS snapshot_version,
64
+ snapshot.plan_version_id AS snapshot_plan_version_id,
65
+ snapshot.verification_status AS snapshot_verification_status,
66
+ snapshot.effective_from AS snapshot_effective_from,
67
+ snapshot.monthly_usage_anchor AS snapshot_monthly_usage_anchor,
68
+ snapshot.entitlements,
69
+ snapshot.content_checksum AS snapshot_content_checksum,
70
+ (
71
+ SELECT count(DISTINCT (deployment.org_slug, deployment.app_slug))::text
72
+ FROM org_billing_links AS link
73
+ JOIN orgs AS org ON org.slug = link.org_slug AND org.slug <> 'local'
74
+ JOIN deploy_records AS deployment
75
+ ON deployment.org_slug = org.slug
76
+ AND deployment.active
77
+ AND deployment.archived_at IS NULL
78
+ WHERE link.billing_account_id = account.id AND link.active
79
+ ) AS production_apps
80
+ FROM billing_accounts AS account
81
+ JOIN billing_account_active_enforcement_profiles AS active_profile
82
+ ON active_profile.billing_account_id = account.id
83
+ JOIN billing_account_enforcement_profiles AS profile
84
+ ON profile.billing_account_id = active_profile.billing_account_id
85
+ AND profile.version = active_profile.profile_version
86
+ JOIN billing_enforcement_cohort_seals AS seal ON seal.singleton = true
87
+ LEFT JOIN billing_account_active_snapshots AS active_snapshot
88
+ ON active_snapshot.billing_account_id = account.id
89
+ LEFT JOIN billing_entitlement_snapshots AS snapshot
90
+ ON snapshot.billing_account_id = active_snapshot.billing_account_id
91
+ AND snapshot.id = active_snapshot.snapshot_id
92
+ ORDER BY account.id
93
+ `);
94
+ let invalidEnforcedEntitlementAccountCount = 0;
95
+ let nonFreeEnforcedAccountCount = 0;
96
+ let enforcedOverCapacityAccountCount = 0;
97
+ let legacyInternalExemptOverCapacityAccountCount = 0;
98
+ for (const row of rows) {
99
+ const productionApps = parseCount(row.production_apps);
100
+ let limit;
101
+ try {
102
+ if (row.mode === 'enforced')
103
+ validateEnforcedSnapshot(row);
104
+ parseBillingCommercialUsageEntitlements(row.entitlements);
105
+ limit = productionAppLimit(row.entitlements);
106
+ if (row.mode === 'enforced' && !isBillingCommercialFreeV1Entitlements(row.entitlements)) {
107
+ nonFreeEnforcedAccountCount += 1;
108
+ }
109
+ }
110
+ catch {
111
+ if (row.mode === 'enforced')
112
+ invalidEnforcedEntitlementAccountCount += 1;
113
+ continue;
114
+ }
115
+ if (productionApps <= limit)
116
+ continue;
117
+ if (row.mode === 'enforced')
118
+ enforcedOverCapacityAccountCount += 1;
119
+ else if (row.mode === 'legacy_internal_exempt') {
120
+ legacyInternalExemptOverCapacityAccountCount += 1;
121
+ }
122
+ }
123
+ return {
124
+ invalidEnforcedEntitlementAccountCount,
125
+ nonFreeEnforcedAccountCount,
126
+ enforcedOverCapacityAccountCount,
127
+ legacyInternalExemptOverCapacityAccountCount,
128
+ };
129
+ }
130
+ function validateEnforcedSnapshot(row) {
131
+ const profileEffectiveFrom = persistedInstant(row.profile_effective_from);
132
+ const cohortSealedAt = persistedInstant(row.cohort_sealed_at);
133
+ if (row.account_state !== 'active' ||
134
+ row.profile_source !== 'post_seal_account' ||
135
+ row.profile_cohort_seal_id !== row.cohort_seal_id ||
136
+ profileEffectiveFrom < cohortSealedAt ||
137
+ row.snapshot_id === null ||
138
+ row.snapshot_version === null ||
139
+ !Number.isSafeInteger(row.snapshot_version) ||
140
+ row.snapshot_version < 1 ||
141
+ row.snapshot_plan_version_id === null ||
142
+ row.snapshot_verification_status !== 'verified' ||
143
+ row.snapshot_effective_from === null ||
144
+ row.snapshot_monthly_usage_anchor === null ||
145
+ row.snapshot_content_checksum === null) {
146
+ throw new Error('enforced billing snapshot is invalid');
147
+ }
148
+ const effectiveFrom = persistedInstant(row.snapshot_effective_from);
149
+ const monthlyUsageAnchor = persistedInstant(row.snapshot_monthly_usage_anchor);
150
+ const expectedChecksum = billingContentChecksum({
151
+ billingAccountId: row.account_id,
152
+ version: row.snapshot_version,
153
+ planVersionId: row.snapshot_plan_version_id,
154
+ effectiveFrom,
155
+ monthlyUsageAnchor,
156
+ entitlements: row.entitlements,
157
+ });
158
+ if (row.snapshot_content_checksum !== expectedChecksum) {
159
+ throw new Error('enforced billing snapshot checksum is invalid');
160
+ }
161
+ }
162
+ function productionAppLimit(entitlements) {
163
+ if (entitlements === null || typeof entitlements !== 'object' || Array.isArray(entitlements)) {
164
+ throw new Error('production app entitlement is invalid');
165
+ }
166
+ const value = entitlements['apps.production.max'];
167
+ if (!Number.isSafeInteger(value) || value < 0) {
168
+ throw new Error('production app entitlement is invalid');
169
+ }
170
+ return value;
171
+ }
172
+ function parseCount(value) {
173
+ const parsed = Number(value);
174
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
175
+ throw new Error('production app footprint count is invalid');
176
+ }
177
+ return parsed;
178
+ }
179
+ function persistedInstant(value) {
180
+ const date = value instanceof Date ? value : new Date(value);
181
+ if (!Number.isFinite(date.getTime()))
182
+ throw new Error('billing preflight timestamp is invalid');
183
+ return date.toISOString();
184
+ }
185
+ function resolveOptions(options) {
186
+ return {
187
+ serviceOrigin: normalizeActivationServiceUrl(options.serviceOrigin),
188
+ currentReleaseSha: validateReleaseSha(options.currentReleaseSha),
189
+ supportedAdmissionContractVersion: validateAdmissionContractVersion(options.supportedAdmissionContractVersion ?? BILLING_AUTHORITATIVE_ADMISSION_CONTRACT_VERSION),
190
+ ...(options.meterReadiness === undefined ? {} : { meterReadiness: options.meterReadiness }),
191
+ };
192
+ }
193
+ //# sourceMappingURL=postgres-enforcement-activation-preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-enforcement-activation-preflight.js","sourceRoot":"","sources":["../../src/billing/postgres-enforcement-activation-preflight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Pool } from 'pg';
2
+ /** Durable admission switch and immutable operation evidence. Schema creation never activates billing. */
3
+ export declare function ensureBillingEnforcementActivationSchema(pool: Pool): Promise<void>;
4
+ //# sourceMappingURL=postgres-enforcement-activation-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-enforcement-activation-schema.d.ts","sourceRoot":"","sources":["../../src/billing/postgres-enforcement-activation-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAE/B,0GAA0G;AAC1G,wBAAsB,wCAAwC,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAoHxF"}
@@ -0,0 +1,119 @@
1
+ /** Durable admission switch and immutable operation evidence. Schema creation never activates billing. */
2
+ export async function ensureBillingEnforcementActivationSchema(pool) {
3
+ await pool.query(`
4
+ CREATE TABLE IF NOT EXISTS billing_enforcement_activation_state (
5
+ singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton),
6
+ schema_version integer NOT NULL CHECK (schema_version = 1),
7
+ state text NOT NULL
8
+ CHECK (state IN ('not_activated', 'active', 'rolled_back')),
9
+ generation integer NOT NULL CHECK (generation >= 0),
10
+ cohort_seal_id text NOT NULL
11
+ REFERENCES billing_enforcement_cohort_seals(id) ON DELETE RESTRICT,
12
+ active_epoch_id text REFERENCES billing_meter_epochs(id) ON DELETE RESTRICT,
13
+ last_epoch_id text REFERENCES billing_meter_epochs(id) ON DELETE RESTRICT,
14
+ activated_at timestamptz,
15
+ rolled_back_at timestamptz,
16
+ activation_service_release_sha text
17
+ CHECK (
18
+ activation_service_release_sha IS NULL OR
19
+ activation_service_release_sha ~ '^[0-9a-f]{40}$'
20
+ ),
21
+ admission_contract_version integer CHECK (admission_contract_version > 0),
22
+ approval_checksum text
23
+ CHECK (approval_checksum IS NULL OR approval_checksum ~ '^[0-9a-f]{64}$'),
24
+ created_at timestamptz NOT NULL,
25
+ updated_at timestamptz NOT NULL CHECK (updated_at >= created_at),
26
+ CHECK (
27
+ (
28
+ state = 'not_activated' AND generation = 0 AND active_epoch_id IS NULL AND
29
+ last_epoch_id IS NULL AND activated_at IS NULL AND rolled_back_at IS NULL AND
30
+ activation_service_release_sha IS NULL AND admission_contract_version IS NULL AND
31
+ approval_checksum IS NULL
32
+ ) OR (
33
+ state = 'active' AND generation > 0 AND active_epoch_id IS NOT NULL AND
34
+ active_epoch_id = last_epoch_id AND activated_at IS NOT NULL AND rolled_back_at IS NULL AND
35
+ activation_service_release_sha IS NOT NULL AND admission_contract_version IS NOT NULL AND
36
+ approval_checksum IS NOT NULL
37
+ ) OR (
38
+ state = 'rolled_back' AND generation > 0 AND active_epoch_id IS NULL AND
39
+ last_epoch_id IS NOT NULL AND activated_at IS NOT NULL AND rolled_back_at IS NOT NULL AND
40
+ rolled_back_at >= activated_at AND activation_service_release_sha IS NOT NULL AND
41
+ admission_contract_version IS NOT NULL AND approval_checksum IS NOT NULL
42
+ )
43
+ )
44
+ )
45
+ `);
46
+ await pool.query(`
47
+ CREATE TABLE IF NOT EXISTS billing_enforcement_activation_operations (
48
+ operation_id text PRIMARY KEY,
49
+ activation_state_singleton boolean NOT NULL DEFAULT true
50
+ REFERENCES billing_enforcement_activation_state(singleton) ON DELETE RESTRICT,
51
+ action text NOT NULL CHECK (action IN ('activate', 'rollback')),
52
+ idempotency_key_hash text NOT NULL UNIQUE
53
+ CHECK (idempotency_key_hash ~ '^[0-9a-f]{64}$'),
54
+ request_fingerprint text NOT NULL CHECK (request_fingerprint ~ '^[0-9a-f]{64}$'),
55
+ generation integer NOT NULL CHECK (generation > 0),
56
+ epoch_id text NOT NULL REFERENCES billing_meter_epochs(id) ON DELETE RESTRICT,
57
+ validation_epoch_id text REFERENCES billing_meter_epochs(id) ON DELETE RESTRICT,
58
+ approval_checksum text NOT NULL CHECK (approval_checksum ~ '^[0-9a-f]{64}$'),
59
+ preview_checksum text CHECK (
60
+ preview_checksum IS NULL OR preview_checksum ~ '^[0-9a-f]{64}$'
61
+ ),
62
+ result jsonb NOT NULL,
63
+ actor_subject text NOT NULL,
64
+ actor_email text NOT NULL,
65
+ service_origin text NOT NULL,
66
+ reason text NOT NULL,
67
+ created_at timestamptz NOT NULL,
68
+ UNIQUE (action, epoch_id),
69
+ CHECK (
70
+ (action = 'activate' AND validation_epoch_id IS NOT NULL AND preview_checksum IS NOT NULL) OR
71
+ (action = 'rollback' AND validation_epoch_id IS NULL AND preview_checksum IS NULL)
72
+ )
73
+ )
74
+ `);
75
+ await pool.query(`
76
+ CREATE OR REPLACE FUNCTION initialize_billing_enforcement_activation_state()
77
+ RETURNS trigger LANGUAGE plpgsql AS $$
78
+ BEGIN
79
+ INSERT INTO billing_enforcement_activation_state
80
+ (singleton, schema_version, state, generation, cohort_seal_id, created_at, updated_at)
81
+ VALUES (true, 1, 'not_activated', 0, NEW.id, NEW.sealed_at, NEW.sealed_at)
82
+ ON CONFLICT (singleton) DO NOTHING;
83
+ RETURN NEW;
84
+ END
85
+ $$
86
+ `);
87
+ await pool.query(`
88
+ DO $billing_enforcement_activation_trigger$
89
+ BEGIN
90
+ IF NOT EXISTS (
91
+ SELECT 1 FROM pg_trigger
92
+ WHERE tgname = 'billing_enforcement_cohort_initialize_activation_state'
93
+ AND tgrelid = 'billing_enforcement_cohort_seals'::regclass
94
+ AND NOT tgisinternal
95
+ ) THEN
96
+ CREATE TRIGGER billing_enforcement_cohort_initialize_activation_state
97
+ AFTER INSERT ON billing_enforcement_cohort_seals
98
+ FOR EACH ROW EXECUTE FUNCTION initialize_billing_enforcement_activation_state();
99
+ END IF;
100
+ END
101
+ $billing_enforcement_activation_trigger$
102
+ `);
103
+ // Safe one-time upgrade for environments sealed before this schema existed. A history-bearing state can
104
+ // never be recreated because operation rows reference the singleton with DELETE RESTRICT.
105
+ await pool.query(`
106
+ INSERT INTO billing_enforcement_activation_state
107
+ (singleton, schema_version, state, generation, cohort_seal_id, created_at, updated_at)
108
+ SELECT true, 1, 'not_activated', 0, seal.id, seal.sealed_at, seal.sealed_at
109
+ FROM billing_enforcement_cohort_seals AS seal
110
+ WHERE seal.singleton = true
111
+ AND NOT EXISTS (SELECT 1 FROM billing_enforcement_activation_state)
112
+ AND NOT EXISTS (SELECT 1 FROM billing_enforcement_activation_operations)
113
+ AND NOT EXISTS (
114
+ SELECT 1 FROM billing_meter_epochs WHERE purpose = 'authoritative'
115
+ )
116
+ ON CONFLICT (singleton) DO NOTHING
117
+ `);
118
+ }
119
+ //# sourceMappingURL=postgres-enforcement-activation-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-enforcement-activation-schema.js","sourceRoot":"","sources":["../../src/billing/postgres-enforcement-activation-schema.ts"],"names":[],"mappings":"AAEA,0GAA0G;AAC1G,MAAM,CAAC,KAAK,UAAU,wCAAwC,CAAC,IAAU;IACvE,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0ChB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;GAWhB,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;GAehB,CAAC,CAAC;IACH,wGAAwG;IACxG,0FAA0F;IAC1F,MAAM,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;GAYhB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,65 @@
1
+ import type { PoolClient, QueryResultRow } from 'pg';
2
+ import type { ControlPlaneIdentity } from '../auth/deploy-gate.js';
3
+ import { type BillingEnforcementActivationApproval, type BillingEnforcementActivationMutationResult, type BillingEnforcementActivationStatus } from './enforcement-activation.js';
4
+ export interface ActivationStateRow extends QueryResultRow {
5
+ readonly state: 'not_activated' | 'active' | 'rolled_back';
6
+ readonly generation: number;
7
+ readonly cohort_seal_id: string;
8
+ readonly active_epoch_id: string | null;
9
+ readonly last_epoch_id: string | null;
10
+ readonly activated_at: Date | string | null;
11
+ readonly rolled_back_at: Date | string | null;
12
+ readonly activation_service_release_sha: string | null;
13
+ readonly admission_contract_version: number | null;
14
+ readonly approval_checksum: string | null;
15
+ }
16
+ export interface EpochRow extends QueryResultRow {
17
+ readonly id: string;
18
+ readonly purpose: 'validation' | 'authoritative';
19
+ readonly state: 'prepared' | 'active' | 'retired';
20
+ readonly key_generation: string;
21
+ readonly release_sha: string;
22
+ readonly retry_identity_version: number;
23
+ readonly writer_contract_version: number;
24
+ readonly admission_contract_version: number;
25
+ }
26
+ export interface OperationRow extends QueryResultRow {
27
+ readonly action: 'activate' | 'rollback';
28
+ readonly request_fingerprint: string;
29
+ readonly result: unknown;
30
+ }
31
+ export declare function requireActivationState(client: PoolClient, forUpdate: boolean): Promise<ActivationStateRow>;
32
+ export declare function stateRowToStatus(row: ActivationStateRow): BillingEnforcementActivationStatus;
33
+ export declare function assertExpectedInactiveState(state: ActivationStateRow, approval: BillingEnforcementActivationApproval): void;
34
+ export declare function requirePreparedValidationEpoch(client: PoolClient, epochId: string): Promise<EpochRow>;
35
+ export declare function requireActiveAuthoritativeEpoch(client: PoolClient, epochId: string): Promise<EpochRow>;
36
+ export declare function assertValidationEpochBindings(epoch: EpochRow, expected: {
37
+ readonly releaseSha: string;
38
+ readonly admissionContractVersion: number;
39
+ }): void;
40
+ export declare function assertActivationConfiguration(approval: BillingEnforcementActivationApproval, expected: {
41
+ readonly service: string;
42
+ readonly releaseSha: string;
43
+ }): void;
44
+ export declare function findOperation(client: PoolClient, idempotencyHash: string): Promise<OperationRow | undefined>;
45
+ export declare function replayOperation(row: OperationRow, action: 'activate' | 'rollback', fingerprint: string): BillingEnforcementActivationMutationResult;
46
+ export declare function insertOperation(client: PoolClient, input: {
47
+ readonly result: BillingEnforcementActivationMutationResult;
48
+ readonly idempotencyHash: string;
49
+ readonly fingerprint: string;
50
+ readonly actor: ControlPlaneIdentity;
51
+ readonly service: string;
52
+ readonly reason: string;
53
+ readonly validationEpochId: string | null;
54
+ readonly createdAt: string;
55
+ readonly operationId: string;
56
+ }): Promise<void>;
57
+ export declare function writeSuccessAudit(client: PoolClient, result: BillingEnforcementActivationMutationResult, actor: ControlPlaneIdentity): Promise<void>;
58
+ export declare function normalizeActor(actor: ControlPlaneIdentity): ControlPlaneIdentity;
59
+ export declare function hashIdempotencyKey(value: string): string;
60
+ export declare function validateReleaseSha(value: string): string;
61
+ export declare function validateAdmissionContractVersion(value: number): number;
62
+ export declare function translateTransactionError(error: unknown): unknown;
63
+ export declare function toIso(value: Date | string): string;
64
+ export declare function rollbackQuietly(client: PoolClient): Promise<void>;
65
+ //# sourceMappingURL=postgres-enforcement-activation-support.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-enforcement-activation-support.d.ts","sourceRoot":"","sources":["../../src/billing/postgres-enforcement-activation-support.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { insertAuditEvent } from '@noodle-borg/module-audit';
3
+ import { BILLING_AUTHORITATIVE_ADMISSION_CONTRACT_VERSION, BillingEnforcementActivationConflictError, BillingEnforcementActivationMutationResultSchema, BillingEnforcementActivationStatusSchema, billingEnforcementActivationSuccessAudit, } from './enforcement-activation.js';
4
+ import { normalizeBillingEmail } from './model.js';
5
+ import { readBillingMeterTransactionTime } from './postgres-meter-clock.js';
6
+ import { validateScalarId } from './postgres-records.js';
7
+ export async function requireActivationState(client, forUpdate) {
8
+ const { rows } = await client.query(`SELECT * FROM billing_enforcement_activation_state WHERE singleton = true${forUpdate ? ' FOR UPDATE' : ''}`);
9
+ const row = rows[0];
10
+ if (row === undefined) {
11
+ throw new BillingEnforcementActivationConflictError('activation_configuration_unavailable', 'sealed billing enforcement requires an explicit activation state');
12
+ }
13
+ return row;
14
+ }
15
+ export function stateRowToStatus(row) {
16
+ return BillingEnforcementActivationStatusSchema.parse({
17
+ schemaVersion: 1,
18
+ state: row.state,
19
+ generation: row.generation,
20
+ cohortSealId: validateScalarId('billing enforcement cohort seal id', row.cohort_seal_id),
21
+ activeEpochId: row.active_epoch_id,
22
+ lastEpochId: row.last_epoch_id,
23
+ activatedAt: row.activated_at === null ? null : toIso(row.activated_at),
24
+ rolledBackAt: row.rolled_back_at === null ? null : toIso(row.rolled_back_at),
25
+ activationServiceReleaseSha: row.activation_service_release_sha,
26
+ admissionContractVersion: row.admission_contract_version,
27
+ approvalChecksum: row.approval_checksum,
28
+ });
29
+ }
30
+ export function assertExpectedInactiveState(state, approval) {
31
+ if (state.state !== approval.expectedState ||
32
+ state.generation !== approval.expectedGeneration ||
33
+ state.cohort_seal_id !== approval.expectedCohortSealId ||
34
+ state.active_epoch_id !== null) {
35
+ throw new BillingEnforcementActivationConflictError('activation_state_conflict', 'billing enforcement activation state does not match the approved preview');
36
+ }
37
+ }
38
+ export async function requirePreparedValidationEpoch(client, epochId) {
39
+ const { rows } = await client.query(`SELECT id, purpose, state, key_generation, release_sha, retry_identity_version,
40
+ writer_contract_version, admission_contract_version
41
+ FROM billing_meter_epochs WHERE id = $1 FOR UPDATE`, [validateScalarId('billing meter validation epoch id', epochId)]);
42
+ const row = rows[0];
43
+ if (row === undefined || row.purpose !== 'validation' || row.state !== 'prepared') {
44
+ throw new BillingEnforcementActivationConflictError('activation_epoch_conflict', 'approved validation epoch is not prepared');
45
+ }
46
+ return row;
47
+ }
48
+ export async function requireActiveAuthoritativeEpoch(client, epochId) {
49
+ const { rows } = await client.query(`SELECT id, purpose, state, key_generation, release_sha, retry_identity_version,
50
+ writer_contract_version, admission_contract_version
51
+ FROM billing_meter_epochs WHERE id = $1 FOR UPDATE`, [validateScalarId('billing meter authoritative epoch id', epochId)]);
52
+ const row = rows[0];
53
+ if (row === undefined || row.purpose !== 'authoritative' || row.state !== 'active') {
54
+ throw new BillingEnforcementActivationConflictError('activation_epoch_conflict', 'billing enforcement rollback epoch is not active');
55
+ }
56
+ return row;
57
+ }
58
+ export function assertValidationEpochBindings(epoch, expected) {
59
+ if (epoch.release_sha !== expected.releaseSha ||
60
+ epoch.admission_contract_version !== expected.admissionContractVersion) {
61
+ throw new BillingEnforcementActivationConflictError('activation_epoch_conflict', 'prepared validation epoch is not compatible with authoritative admission');
62
+ }
63
+ }
64
+ export function assertActivationConfiguration(approval, expected) {
65
+ if (approval.service !== expected.service ||
66
+ approval.expectedServiceReleaseSha !== expected.releaseSha) {
67
+ throw new BillingEnforcementActivationConflictError('activation_configuration_unavailable', 'activation approval targets a different service or release');
68
+ }
69
+ }
70
+ export async function findOperation(client, idempotencyHash) {
71
+ const { rows } = await client.query(`SELECT action, request_fingerprint, result
72
+ FROM billing_enforcement_activation_operations WHERE idempotency_key_hash = $1`, [idempotencyHash]);
73
+ return rows[0];
74
+ }
75
+ export function replayOperation(row, action, fingerprint) {
76
+ if (row.action !== action || row.request_fingerprint !== fingerprint) {
77
+ throw new BillingEnforcementActivationConflictError('idempotency_key_conflict', 'idempotency key was already used by a different request or actor');
78
+ }
79
+ const result = BillingEnforcementActivationMutationResultSchema.parse(row.result);
80
+ return { ...result, replayed: true };
81
+ }
82
+ export async function insertOperation(client, input) {
83
+ await client.query(`INSERT INTO billing_enforcement_activation_operations
84
+ (operation_id, action, idempotency_key_hash, request_fingerprint, generation,
85
+ epoch_id, validation_epoch_id, approval_checksum, preview_checksum, result,
86
+ actor_subject, actor_email, service_origin, reason, created_at)
87
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10::jsonb, $11, $12, $13, $14, $15)`, [
88
+ input.operationId,
89
+ input.result.action,
90
+ input.idempotencyHash,
91
+ input.fingerprint,
92
+ input.result.generation,
93
+ input.result.lastEpochId,
94
+ input.validationEpochId,
95
+ input.result.approvalChecksum,
96
+ input.result.previewChecksum,
97
+ JSON.stringify(input.result),
98
+ input.actor.subject,
99
+ input.actor.email,
100
+ input.service,
101
+ input.reason,
102
+ input.createdAt,
103
+ ]);
104
+ }
105
+ export async function writeSuccessAudit(client, result, actor) {
106
+ const replayedAt = await readBillingMeterTransactionTime(client);
107
+ await insertAuditEvent(client, billingEnforcementActivationSuccessAudit(result, actor), {
108
+ now: () => new Date(replayedAt),
109
+ });
110
+ }
111
+ export function normalizeActor(actor) {
112
+ return {
113
+ ...actor,
114
+ subject: validateScalarId('billing enforcement activation actor subject', actor.subject),
115
+ email: normalizeBillingEmail(actor.email),
116
+ };
117
+ }
118
+ export function hashIdempotencyKey(value) {
119
+ return createHash('sha256').update(value).digest('hex');
120
+ }
121
+ export function validateReleaseSha(value) {
122
+ if (!/^[0-9a-f]{40}$/.test(value)) {
123
+ throw new Error('billing enforcement activation requires a full lowercase release SHA');
124
+ }
125
+ return value;
126
+ }
127
+ export function validateAdmissionContractVersion(value) {
128
+ if (value !== BILLING_AUTHORITATIVE_ADMISSION_CONTRACT_VERSION || !Number.isSafeInteger(value)) {
129
+ throw new Error('billing enforcement admission contract version is unsupported');
130
+ }
131
+ return value;
132
+ }
133
+ export function translateTransactionError(error) {
134
+ const code = typeof error === 'object' && error !== null && 'code' in error
135
+ ? String(error.code)
136
+ : undefined;
137
+ if (code === '40001' || code === '40P01') {
138
+ return new BillingEnforcementActivationConflictError('serialization_conflict', 'billing enforcement activation state changed concurrently; retry the exact request');
139
+ }
140
+ if (code === '55P03') {
141
+ return new BillingEnforcementActivationConflictError('activation_lock_timeout', 'billing enforcement activation lock wait timed out; retry the exact request');
142
+ }
143
+ return error;
144
+ }
145
+ export function toIso(value) {
146
+ const date = value instanceof Date ? value : new Date(value);
147
+ if (!Number.isFinite(date.getTime()))
148
+ throw new Error('billing enforcement timestamp is invalid');
149
+ return date.toISOString();
150
+ }
151
+ export async function rollbackQuietly(client) {
152
+ try {
153
+ await client.query('ROLLBACK');
154
+ }
155
+ catch {
156
+ // Preserve the original transaction failure.
157
+ }
158
+ }
159
+ //# sourceMappingURL=postgres-enforcement-activation-support.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-enforcement-activation-support.js","sourceRoot":"","sources":["../../src/billing/postgres-enforcement-activation-support.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { Pool } from 'pg';
2
+ import type { ControlPlaneIdentity } from '../auth/deploy-gate.js';
3
+ import { type BillingEnforcementActivateRequest, type BillingEnforcementActivationApproval, type BillingEnforcementActivationMutationResult, type BillingEnforcementActivationPreflight, type BillingEnforcementActivationPreview, type BillingEnforcementActivationStatus, type BillingEnforcementActivationStore, type BillingEnforcementRollbackRequest } from './enforcement-activation.js';
4
+ export interface PostgresBillingEnforcementActivationStoreOptions {
5
+ readonly currentReleaseSha: string;
6
+ readonly admissionContractVersion?: number;
7
+ readonly preflight: BillingEnforcementActivationPreflight;
8
+ readonly lockTimeoutMs?: number;
9
+ readonly id?: () => string;
10
+ }
11
+ /** PostgreSQL-only protected lifecycle. The callback performs readiness checks on this store's transaction. */
12
+ export declare class PostgresBillingEnforcementActivationStore implements BillingEnforcementActivationStore {
13
+ #private;
14
+ readonly successAuditMode: "transactional";
15
+ constructor(pool: Pool, options: PostgresBillingEnforcementActivationStoreOptions);
16
+ getActivationStatus(): Promise<BillingEnforcementActivationStatus>;
17
+ previewActivation(input: {
18
+ readonly approval: BillingEnforcementActivationApproval;
19
+ }): Promise<BillingEnforcementActivationPreview>;
20
+ activateEnforcement(input: {
21
+ readonly request: BillingEnforcementActivateRequest;
22
+ readonly actor: ControlPlaneIdentity;
23
+ readonly service: string;
24
+ }): Promise<BillingEnforcementActivationMutationResult>;
25
+ rollbackEnforcement(input: {
26
+ readonly request: BillingEnforcementRollbackRequest;
27
+ readonly actor: ControlPlaneIdentity;
28
+ readonly service: string;
29
+ }): Promise<BillingEnforcementActivationMutationResult>;
30
+ }
31
+ //# sourceMappingURL=postgres-enforcement-activation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-enforcement-activation.d.ts","sourceRoot":"","sources":["../../src/billing/postgres-enforcement-activation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAEL,KAAK,iCAAiC,EACtC,KAAK,oCAAoC,EAEzC,KAAK,0CAA0C,EAE/C,KAAK,qCAAqC,EAC1C,KAAK,mCAAmC,EAExC,KAAK,kCAAkC,EACvC,KAAK,iCAAiC,EACtC,KAAK,iCAAiC,EAOvC,MAAM,6BAA6B,CAAC;AA2BrC,MAAM,WAAW,gDAAgD;IAC/D,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,qCAAqC,CAAC;IAC1D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED,+GAA+G;AAC/G,qBAAa,yCACX,YAAW,iCAAiC;;IAE5C,QAAQ,CAAC,gBAAgB,EAAG,eAAe,CAAU;gBAQzC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,gDAAgD;IAa3E,mBAAmB,IAAI,OAAO,CAAC,kCAAkC,CAAC;IAgBlE,iBAAiB,CAAC,KAAK,EAAE;QAC7B,QAAQ,CAAC,QAAQ,EAAE,oCAAoC,CAAC;KACzD,GAAG,OAAO,CAAC,mCAAmC,CAAC;IAmBhD,mBAAmB,CAAC,KAAK,EAAE;QACzB,QAAQ,CAAC,OAAO,EAAE,iCAAiC,CAAC;QACpD,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;QACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,GAAG,OAAO,CAAC,0CAA0C,CAAC;IAOvD,mBAAmB,CAAC,KAAK,EAAE;QACzB,QAAQ,CAAC,OAAO,EAAE,iCAAiC,CAAC;QACpD,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;QACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,GAAG,OAAO,CAAC,0CAA0C,CAAC;CA4PxD"}