@greatwait/contracts 0.1.0-alpha.3 → 0.1.0-alpha.4

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 (299) hide show
  1. package/README.md +11 -9
  2. package/dist/authority.d.ts +33 -27
  3. package/dist/authority.js +12 -2
  4. package/dist/billing.d.ts +1001 -0
  5. package/dist/billing.js +684 -0
  6. package/dist/callback-safety.d.ts +2 -2
  7. package/dist/callback-safety.js +2 -2
  8. package/dist/compatibility.d.ts +3 -3
  9. package/dist/compatibility.js +1 -1
  10. package/dist/data-export.d.ts +67 -0
  11. package/dist/data-export.js +182 -0
  12. package/dist/endpoints.d.ts +181 -240
  13. package/dist/endpoints.js +77 -81
  14. package/dist/events.d.ts +17 -17
  15. package/dist/events.js +1 -1
  16. package/dist/first-value-journey.d.ts +49 -55
  17. package/dist/first-value-journey.js +6 -13
  18. package/dist/forecast.d.ts +71 -71
  19. package/dist/forecast.js +1 -1
  20. package/dist/identifiers.d.ts +20 -20
  21. package/dist/identifiers.js +1 -1
  22. package/dist/identity.d.ts +41 -37
  23. package/dist/identity.js +5 -4
  24. package/dist/index.d.ts +10 -5
  25. package/dist/index.js +10 -5
  26. package/dist/mcp.d.ts +21 -19
  27. package/dist/mcp.js +1 -1
  28. package/dist/naming.d.ts +45 -0
  29. package/dist/naming.js +159 -0
  30. package/dist/oauth.d.ts +186 -172
  31. package/dist/oauth.js +1 -1
  32. package/dist/operation-definitions.d.ts +9 -0
  33. package/dist/operation-definitions.js +7 -0
  34. package/dist/operations.d.ts +4162 -2171
  35. package/dist/operations.js +2679 -908
  36. package/dist/organization-lifecycle.d.ts +34 -0
  37. package/dist/organization-lifecycle.js +122 -0
  38. package/dist/partition.d.ts +26 -0
  39. package/dist/policy.d.ts +4 -4
  40. package/dist/policy.js +9 -5
  41. package/dist/problems.d.ts +32 -26
  42. package/dist/problems.js +6 -2
  43. package/dist/protocol.d.ts +204 -75
  44. package/dist/protocol.js +108 -36
  45. package/dist/scheduling-records.d.ts +343 -285
  46. package/dist/scheduling-records.js +1 -1
  47. package/dist/scheduling.d.ts +670 -360
  48. package/dist/scheduling.js +382 -56
  49. package/dist/secrets.d.ts +119 -105
  50. package/dist/secrets.js +1 -1
  51. package/dist/signatures.d.ts +74 -74
  52. package/dist/signatures.js +1 -1
  53. package/dist/tenancy.d.ts +142 -68
  54. package/dist/tenancy.js +70 -17
  55. package/dist/test-sink.d.ts +127 -127
  56. package/dist/test-sink.js +1 -1
  57. package/dist/time.d.ts +4 -4
  58. package/dist/time.js +1 -1
  59. package/dist/timing.d.ts +65 -0
  60. package/dist/timing.js +82 -0
  61. package/dist/usage.d.ts +103 -47
  62. package/dist/usage.js +197 -31
  63. package/dist/workspace.d.ts +34 -34
  64. package/dist/workspace.js +1 -1
  65. package/dist/zod-values.d.ts +3 -0
  66. package/dist/zod-values.js +2 -0
  67. package/dist/zod.d.ts +2 -0
  68. package/dist/zod.js +2 -0
  69. package/generated/v1/examples/attempts.list.response.json +4 -0
  70. package/generated/v1/examples/attempts.read.response.json +4 -0
  71. package/generated/v1/examples/billing.autotopup.request.json +5 -0
  72. package/generated/v1/examples/billing.autotopup.response.json +120 -0
  73. package/generated/v1/examples/billing.autotopuppreview.request.json +19 -0
  74. package/generated/v1/examples/billing.autotopuppreview.response.json +45 -0
  75. package/generated/v1/examples/billing.budgets.request.json +13 -0
  76. package/generated/v1/examples/billing.budgets.response.json +22 -0
  77. package/generated/v1/examples/billing.ceiling.request.json +8 -0
  78. package/generated/v1/examples/billing.ceiling.response.json +120 -0
  79. package/generated/v1/examples/billing.change.request.json +5 -0
  80. package/generated/v1/examples/billing.change.response.json +12 -0
  81. package/generated/v1/examples/billing.funding.response.json +120 -0
  82. package/generated/v1/examples/billing.fundingquote.request.json +7 -0
  83. package/generated/v1/examples/billing.fundingquote.response.json +13 -0
  84. package/generated/v1/examples/billing.ledger.response.json +23 -0
  85. package/generated/v1/examples/billing.notices.response.json +41 -0
  86. package/generated/v1/examples/billing.notificationsettings.response.json +17 -0
  87. package/generated/v1/examples/billing.notificationsettingsupdate.request.json +9 -0
  88. package/generated/v1/examples/billing.notificationsettingsupdate.response.json +17 -0
  89. package/generated/v1/examples/billing.portal.response.json +3 -0
  90. package/generated/v1/examples/billing.projects.response.json +12 -0
  91. package/generated/v1/examples/billing.purchase.request.json +5 -0
  92. package/generated/v1/examples/billing.purchase.response.json +120 -0
  93. package/generated/v1/examples/billing.quote.request.json +4 -0
  94. package/generated/v1/examples/billing.quote.response.json +19 -0
  95. package/generated/v1/examples/billing.reconcile.response.json +73 -0
  96. package/generated/v1/examples/billing.refundrequest.request.json +10 -0
  97. package/generated/v1/examples/billing.refundrequest.response.json +11 -0
  98. package/generated/v1/examples/billing.refundresolution.request.json +4 -0
  99. package/generated/v1/examples/billing.refundresolution.response.json +120 -0
  100. package/generated/v1/examples/billing.summary.response.json +73 -0
  101. package/generated/v1/examples/endpoints.acknowledgeSigningKeyRotation.response.json +18 -0
  102. package/generated/v1/examples/endpoints.create.response.json +1 -1
  103. package/generated/v1/examples/endpoints.disable.response.json +0 -1
  104. package/generated/v1/examples/{endpoints.verify.response.json → endpoints.enable.response.json} +4 -5
  105. package/generated/v1/examples/endpoints.list.response.json +1 -2
  106. package/generated/v1/examples/endpoints.read.response.json +2 -2
  107. package/generated/v1/examples/endpoints.revealSigningSecret.response.json +7 -0
  108. package/generated/v1/examples/endpoints.rotateSigningKey.response.json +1 -2
  109. package/generated/v1/examples/endpoints.update.response.json +1 -1
  110. package/generated/v1/examples/executions.list.response.json +20 -0
  111. package/generated/v1/examples/exports.cancel.response.json +11 -0
  112. package/generated/v1/examples/exports.create.request.json +1 -0
  113. package/generated/v1/examples/exports.create.response.json +8 -0
  114. package/generated/v1/examples/exports.part.response.json +5 -0
  115. package/generated/v1/examples/exports.read.response.json +8 -0
  116. package/generated/v1/examples/occurrences.read.response.json +4 -0
  117. package/generated/v1/examples/organizations.close.request.json +5 -0
  118. package/generated/v1/examples/organizations.close.response.json +10 -0
  119. package/generated/v1/examples/organizations.lifecycle.response.json +10 -0
  120. package/generated/v1/examples/organizations.restore.request.json +3 -0
  121. package/generated/v1/examples/organizations.restore.response.json +10 -0
  122. package/generated/v1/examples/projects.archive.request.json +3 -0
  123. package/generated/v1/examples/projects.archive.response.json +14 -0
  124. package/generated/v1/examples/projects.create.response.json +10 -1
  125. package/generated/v1/examples/projects.delete.response.json +9 -0
  126. package/generated/v1/examples/projects.list.response.json +12 -2
  127. package/generated/v1/examples/projects.rename.request.json +3 -0
  128. package/generated/v1/examples/projects.rename.response.json +14 -0
  129. package/generated/v1/examples/schedules.archive.response.json +3 -0
  130. package/generated/v1/examples/schedules.cancel.response.json +3 -0
  131. package/generated/v1/examples/schedules.create.request.json +4 -0
  132. package/generated/v1/examples/schedules.create.response.json +3 -0
  133. package/generated/v1/examples/schedules.list.response.json +3 -0
  134. package/generated/v1/examples/schedules.pause.response.json +3 -0
  135. package/generated/v1/examples/schedules.read.response.json +6 -0
  136. package/generated/v1/examples/schedules.replace.request.json +4 -0
  137. package/generated/v1/examples/schedules.replace.response.json +3 -0
  138. package/generated/v1/examples/schedules.resume.response.json +3 -0
  139. package/generated/v1/examples/timing.summary.response.json +35 -0
  140. package/generated/v1/examples/usage.read.response.json +1 -0
  141. package/generated/v1/first-value-journey.json +19 -10
  142. package/generated/v1/manifest.json +936 -23
  143. package/generated/v1/openapi.json +29983 -5784
  144. package/generated/v1/policy-matrix.json +278 -47
  145. package/generated/v1/schemas/attempts.list.response.json +24 -1
  146. package/generated/v1/schemas/attempts.read.response.json +24 -1
  147. package/generated/v1/schemas/billing.autotopup.request-headers.json +13 -0
  148. package/generated/v1/schemas/billing.autotopup.request.json +22 -0
  149. package/generated/v1/schemas/billing.autotopup.response-headers.json +10 -0
  150. package/generated/v1/schemas/billing.autotopup.response.json +552 -0
  151. package/generated/v1/schemas/billing.autotopuppreview.request.json +77 -0
  152. package/generated/v1/schemas/billing.autotopuppreview.response.json +277 -0
  153. package/generated/v1/schemas/billing.budgets.request-headers.json +13 -0
  154. package/generated/v1/schemas/billing.budgets.request.json +66 -0
  155. package/generated/v1/schemas/billing.budgets.response-headers.json +10 -0
  156. package/generated/v1/schemas/billing.budgets.response.json +92 -0
  157. package/generated/v1/schemas/billing.ceiling.request-headers.json +13 -0
  158. package/generated/v1/schemas/billing.ceiling.request.json +40 -0
  159. package/generated/v1/schemas/billing.ceiling.response-headers.json +10 -0
  160. package/generated/v1/schemas/billing.ceiling.response.json +552 -0
  161. package/generated/v1/schemas/billing.change.request-headers.json +13 -0
  162. package/generated/v1/schemas/billing.change.request.json +22 -0
  163. package/generated/v1/schemas/billing.change.response.json +119 -0
  164. package/generated/v1/schemas/billing.funding.response.json +552 -0
  165. package/generated/v1/schemas/billing.fundingquote.request.json +28 -0
  166. package/generated/v1/schemas/billing.fundingquote.response.json +61 -0
  167. package/generated/v1/schemas/billing.ledger.query.json +16 -0
  168. package/generated/v1/schemas/billing.ledger.response.json +125 -0
  169. package/generated/v1/schemas/billing.notices.query.json +16 -0
  170. package/generated/v1/schemas/billing.notices.response.json +278 -0
  171. package/generated/v1/schemas/billing.notificationsettings.response.json +70 -0
  172. package/generated/v1/schemas/billing.notificationsettingsupdate.request-headers.json +13 -0
  173. package/generated/v1/schemas/billing.notificationsettingsupdate.request.json +36 -0
  174. package/generated/v1/schemas/billing.notificationsettingsupdate.response-headers.json +10 -0
  175. package/generated/v1/schemas/billing.notificationsettingsupdate.response.json +70 -0
  176. package/generated/v1/schemas/billing.portal.response.json +11 -0
  177. package/generated/v1/schemas/billing.projects.response.json +119 -0
  178. package/generated/v1/schemas/billing.purchase.request-headers.json +13 -0
  179. package/generated/v1/schemas/billing.purchase.request.json +22 -0
  180. package/generated/v1/schemas/billing.purchase.response-headers.json +10 -0
  181. package/generated/v1/schemas/billing.purchase.response.json +552 -0
  182. package/generated/v1/schemas/billing.quote.request.json +20 -0
  183. package/generated/v1/schemas/billing.quote.response.json +86 -0
  184. package/generated/v1/schemas/billing.reconcile.response.json +468 -0
  185. package/generated/v1/schemas/billing.refundrequest.request-headers.json +13 -0
  186. package/generated/v1/schemas/billing.refundrequest.request.json +42 -0
  187. package/generated/v1/schemas/billing.refundrequest.response-headers.json +10 -0
  188. package/generated/v1/schemas/billing.refundrequest.response.json +45 -0
  189. package/generated/v1/schemas/billing.refundresolution.request-headers.json +13 -0
  190. package/generated/v1/schemas/billing.refundresolution.request.json +61 -0
  191. package/generated/v1/schemas/billing.refundresolution.response-headers.json +10 -0
  192. package/generated/v1/schemas/billing.refundresolution.response.json +552 -0
  193. package/generated/v1/schemas/billing.summary.response.json +468 -0
  194. package/generated/v1/schemas/context.read.response.json +2 -0
  195. package/generated/v1/schemas/credentials.connection.response.json +2 -0
  196. package/generated/v1/schemas/credentials.create.request.json +2 -0
  197. package/generated/v1/schemas/credentials.create.response.json +2 -0
  198. package/generated/v1/schemas/credentials.list.response.json +2 -0
  199. package/generated/v1/schemas/credentials.revoke.response.json +2 -0
  200. package/generated/v1/schemas/credentials.rotate.response.json +4 -0
  201. package/generated/v1/schemas/{endpoints.verify.request-headers.json → endpoints.acknowledgeSigningKeyRotation.request-headers.json} +2 -1
  202. package/generated/v1/schemas/{endpoints.verify.response.json → endpoints.acknowledgeSigningKeyRotation.response.json} +8 -21
  203. package/generated/v1/schemas/endpoints.create.request.json +5 -0
  204. package/generated/v1/schemas/endpoints.create.response.json +8 -21
  205. package/generated/v1/schemas/endpoints.disable.response.json +8 -21
  206. package/generated/v1/schemas/endpoints.enable.response-headers.json +11 -0
  207. package/generated/v1/schemas/endpoints.enable.response.json +87 -0
  208. package/generated/v1/schemas/endpoints.list.response.json +8 -21
  209. package/generated/v1/schemas/endpoints.read.response.json +8 -21
  210. package/generated/v1/schemas/endpoints.revealSigningSecret.response.json +43 -0
  211. package/generated/v1/schemas/endpoints.rotateSigningKey.response.json +8 -21
  212. package/generated/v1/schemas/endpoints.update.request.json +5 -0
  213. package/generated/v1/schemas/endpoints.update.response.json +8 -21
  214. package/generated/v1/schemas/executions.list.query.json +46 -0
  215. package/generated/v1/schemas/executions.list.response.json +116 -0
  216. package/generated/v1/schemas/exports.cancel.response.json +48 -0
  217. package/generated/v1/schemas/exports.create.request.json +6 -0
  218. package/generated/v1/schemas/exports.create.response.json +38 -0
  219. package/generated/v1/schemas/exports.part.query.json +11 -0
  220. package/generated/v1/schemas/exports.part.response.json +22 -0
  221. package/generated/v1/schemas/exports.read.response.json +38 -0
  222. package/generated/v1/schemas/grants.list.response.json +2 -0
  223. package/generated/v1/schemas/grants.revoke.response.json +2 -0
  224. package/generated/v1/schemas/occurrences.list.query.json +5 -0
  225. package/generated/v1/schemas/occurrences.list.response.json +23 -0
  226. package/generated/v1/schemas/occurrences.read.response.json +23 -0
  227. package/generated/v1/schemas/occurrences.redeliver.response.json +24 -1
  228. package/generated/v1/schemas/organizations.close.request.json +20 -0
  229. package/generated/v1/schemas/organizations.close.response.json +68 -0
  230. package/generated/v1/schemas/organizations.lifecycle.response.json +68 -0
  231. package/generated/v1/schemas/organizations.restore.request.json +13 -0
  232. package/generated/v1/schemas/organizations.restore.response.json +68 -0
  233. package/generated/v1/schemas/projects.archive.request-headers.json +11 -0
  234. package/generated/v1/schemas/projects.archive.request.json +10 -0
  235. package/generated/v1/schemas/projects.archive.response-headers.json +11 -0
  236. package/generated/v1/schemas/projects.archive.response.json +79 -0
  237. package/generated/v1/schemas/projects.create.response.json +55 -1
  238. package/generated/v1/schemas/projects.delete.request-headers.json +11 -0
  239. package/generated/v1/schemas/projects.delete.response.json +37 -0
  240. package/generated/v1/schemas/projects.list.response.json +61 -2
  241. package/generated/v1/schemas/projects.rename.request-headers.json +11 -0
  242. package/generated/v1/schemas/projects.rename.request.json +12 -0
  243. package/generated/v1/schemas/projects.rename.response-headers.json +11 -0
  244. package/generated/v1/schemas/projects.rename.response.json +79 -0
  245. package/generated/v1/schemas/schedules.archive.response.json +90 -2
  246. package/generated/v1/schemas/schedules.cancel.response.json +90 -2
  247. package/generated/v1/schemas/schedules.create.request.json +24 -3
  248. package/generated/v1/schemas/schedules.create.response.json +90 -2
  249. package/generated/v1/schemas/schedules.list.query.json +13 -0
  250. package/generated/v1/schemas/schedules.list.response.json +67 -2
  251. package/generated/v1/schemas/schedules.pause.response.json +90 -2
  252. package/generated/v1/schemas/schedules.read.response.json +90 -2
  253. package/generated/v1/schemas/schedules.replace.request.json +24 -3
  254. package/generated/v1/schemas/schedules.replace.response.json +90 -2
  255. package/generated/v1/schemas/schedules.resume.response.json +90 -2
  256. package/generated/v1/schemas/timing.summary.response.json +191 -0
  257. package/generated/v1/schemas/usage.read.query.json +7 -0
  258. package/generated/v1/schemas/usage.read.response.json +36 -1
  259. package/generated/v1/snippets/billing.autotopup.json +6 -0
  260. package/generated/v1/snippets/billing.autotopuppreview.json +6 -0
  261. package/generated/v1/snippets/billing.budgets.json +6 -0
  262. package/generated/v1/snippets/billing.ceiling.json +6 -0
  263. package/generated/v1/snippets/billing.change.json +6 -0
  264. package/generated/v1/snippets/billing.funding.json +6 -0
  265. package/generated/v1/snippets/billing.fundingquote.json +6 -0
  266. package/generated/v1/snippets/billing.ledger.json +6 -0
  267. package/generated/v1/snippets/billing.notices.json +6 -0
  268. package/generated/v1/snippets/billing.notificationsettings.json +6 -0
  269. package/generated/v1/snippets/billing.notificationsettingsupdate.json +6 -0
  270. package/generated/v1/snippets/billing.portal.json +6 -0
  271. package/generated/v1/snippets/billing.projects.json +6 -0
  272. package/generated/v1/snippets/billing.purchase.json +6 -0
  273. package/generated/v1/snippets/billing.quote.json +6 -0
  274. package/generated/v1/snippets/billing.reconcile.json +6 -0
  275. package/generated/v1/snippets/billing.refundrequest.json +6 -0
  276. package/generated/v1/snippets/billing.refundresolution.json +6 -0
  277. package/generated/v1/snippets/billing.summary.json +6 -0
  278. package/generated/v1/snippets/endpoints.acknowledgeSigningKeyRotation.json +6 -0
  279. package/generated/v1/snippets/{endpoints.verify.json → endpoints.enable.json} +3 -3
  280. package/generated/v1/snippets/endpoints.revealSigningSecret.json +6 -0
  281. package/generated/v1/snippets/executions.list.json +6 -0
  282. package/generated/v1/snippets/exports.cancel.json +6 -0
  283. package/generated/v1/snippets/exports.create.json +6 -0
  284. package/generated/v1/snippets/exports.part.json +6 -0
  285. package/generated/v1/snippets/exports.read.json +6 -0
  286. package/generated/v1/snippets/organizations.close.json +6 -0
  287. package/generated/v1/snippets/organizations.lifecycle.json +6 -0
  288. package/generated/v1/snippets/organizations.restore.json +6 -0
  289. package/generated/v1/snippets/projects.archive.json +6 -0
  290. package/generated/v1/snippets/projects.delete.json +6 -0
  291. package/generated/v1/snippets/projects.rename.json +6 -0
  292. package/generated/v1/snippets/schedules.create.json +3 -3
  293. package/generated/v1/snippets/schedules.replace.json +3 -3
  294. package/generated/v1/snippets/timing.summary.json +6 -0
  295. package/package.json +1 -6
  296. package/dist/callback-ownership.d.ts +0 -58
  297. package/dist/callback-ownership.js +0 -71
  298. package/generated/v1/callback-endpoint-verification.json +0 -59
  299. /package/generated/v1/schemas/{endpoints.verify.response-headers.json → endpoints.acknowledgeSigningKeyRotation.response-headers.json} +0 -0
@@ -0,0 +1,684 @@
1
+ import { z } from "./zod.js";
2
+ import { attemptIdSchema, projectIdSchema } from "./identifiers.js";
3
+ import { pageRequestSchema, pageSchema, requiredIdempotencyRequestHeaderSchema, } from "./protocol.js";
4
+ import { timestampSchema } from "./time.js";
5
+ export const BILLING_AMOUNT_SCALE = 6;
6
+ export const BILLING_CURRENCY = "USD";
7
+ /**
8
+ * Exact integer money on the wire.
9
+ *
10
+ * PostgreSQL uses `bigint`; JSON uses a canonical decimal string because a
11
+ * JavaScript number cannot represent every ledger amount without rounding.
12
+ */
13
+ export const microdollarAmountSchema = z
14
+ .string()
15
+ .regex(/^-?(?:0|[1-9]\d*)$/u, "must be a canonical integer decimal string");
16
+ export const nonnegativeMicrodollarAmountSchema = z
17
+ .string()
18
+ .regex(/^(?:0|[1-9]\d*)$/u, "must be a canonical nonnegative integer decimal string");
19
+ export const BILLING_ACTIVATION_MODES = [
20
+ "disabled",
21
+ "shadow",
22
+ "enforced",
23
+ ];
24
+ export const BILLING_BLOCK_REASONS = [
25
+ "billing-state-missing",
26
+ "billing-account-closed",
27
+ "project-ineligible",
28
+ "insufficient-credit",
29
+ "execution-cap-reached",
30
+ ];
31
+ export const BILLING_ENTRY_KINDS = [
32
+ "credit_granted",
33
+ "credit_reversed",
34
+ "attempt_debited",
35
+ "attempt_released",
36
+ "shadow_attempt_debited",
37
+ "shadow_attempt_released",
38
+ "late_evidence_waived",
39
+ "policy_installed",
40
+ "budget_policy_updated",
41
+ "budget_threshold_reached",
42
+ "budget_exhausted",
43
+ "budget_recovered",
44
+ "automatic_charge_ceiling_updated",
45
+ "payment_reserved",
46
+ "payment_submitted",
47
+ "payment_pending",
48
+ "payment_paid",
49
+ "payment_failed",
50
+ "payment_canceled",
51
+ "payment_authentication_required",
52
+ "payment_action_required",
53
+ "payment_refunded",
54
+ "payment_disputed",
55
+ "payment_reversed",
56
+ "payment_dispute_restored",
57
+ "refund_requested",
58
+ "payment_refund_canceled",
59
+ "automatic_top_up_cap_reached",
60
+ "automatic_charge_threshold_reached",
61
+ "automatic_charge_threshold_recovered",
62
+ "low_credit_reached",
63
+ "low_credit_recovered",
64
+ "notification_settings_updated",
65
+ "service_blocked",
66
+ "service_restored",
67
+ ];
68
+ export const BILLING_PAYMENT_KINDS = ["manual", "automatic"];
69
+ export const BILLING_PAYMENT_STATES = [
70
+ "pending",
71
+ "paid",
72
+ "failed",
73
+ "authentication-required",
74
+ "action-required",
75
+ "canceled",
76
+ "refunded",
77
+ "reversed",
78
+ "disputed",
79
+ ];
80
+ const signedExactMoneySchema = z.object({
81
+ currency: z.literal(BILLING_CURRENCY),
82
+ microdollars: microdollarAmountSchema,
83
+ scale: z.literal(BILLING_AMOUNT_SCALE),
84
+ });
85
+ const nonnegativeExactMoneySchema = z.object({
86
+ currency: z.literal(BILLING_CURRENCY),
87
+ microdollars: nonnegativeMicrodollarAmountSchema,
88
+ scale: z.literal(BILLING_AMOUNT_SCALE),
89
+ });
90
+ /**
91
+ * The generated request contract for a whole-cent PostgreSQL `bigint`.
92
+ *
93
+ * Zod refinements deliberately remain the runtime authority below, while this
94
+ * JSON Schema metadata gives OpenAPI and MCP validators the same boundary. The
95
+ * long final branch is the inclusive 15-digit cent maximum
96
+ * `922337203685477`, followed by the four zero microdollar places.
97
+ */
98
+ const exactCentMicrodollarAmountSchema = nonnegativeMicrodollarAmountSchema.meta({
99
+ description: "A canonical nonnegative integer multiple of 10,000 microdollars, no greater than 9,223,372,036,854,770,000.",
100
+ maxLength: 19,
101
+ pattern: "^(?:0|(?:[1-9]\\d{0,13}|[1-8]\\d{14}|9[01]\\d{13}|92[01]\\d{12}|922[0-2]\\d{11}|9223[0-2]\\d{10}|92233[0-6]\\d{9}|922337[01]\\d{8}|92233720[0-2]\\d{6}|922337203[0-5]\\d{5}|9223372036[0-7]\\d{4}|92233720368[0-4]\\d{3}|922337203685[0-3]\\d{2}|9223372036854[0-6]\\d|92233720368547[0-7])0000)$",
102
+ });
103
+ export const exactCentMoneySchema = z
104
+ .object({
105
+ currency: z.literal(BILLING_CURRENCY),
106
+ microdollars: exactCentMicrodollarAmountSchema,
107
+ scale: z.literal(BILLING_AMOUNT_SCALE),
108
+ })
109
+ .superRefine((amount, context) => {
110
+ const microdollars = BigInt(amount.microdollars);
111
+ if (microdollars % 10000n !== 0n) {
112
+ context.addIssue({
113
+ code: z.ZodIssueCode.custom,
114
+ message: "must be a whole number of cents (10,000 microdollars)",
115
+ path: ["microdollars"],
116
+ });
117
+ }
118
+ if (microdollars > 9223372036854770000n) {
119
+ context.addIssue({
120
+ code: z.ZodIssueCode.custom,
121
+ message: "must fit the exact PostgreSQL billing range",
122
+ path: ["microdollars"],
123
+ });
124
+ }
125
+ });
126
+ export const manualFundingCreditSchema = exactCentMoneySchema.refine((amount) => BigInt(amount.microdollars) >= 10000000n, "manual execution-credit purchases must be at least USD 10");
127
+ const positiveExactCentMoneySchema = exactCentMoneySchema.refine((amount) => BigInt(amount.microdollars) > 0n, "must be greater than zero");
128
+ export const billingAutoTopUpConfigurationSchema = z
129
+ .object({
130
+ ceiling: positiveExactCentMoneySchema,
131
+ credit: positiveExactCentMoneySchema,
132
+ triggerBelow: positiveExactCentMoneySchema,
133
+ })
134
+ .strict()
135
+ .superRefine((configuration, context) => {
136
+ if (BigInt(configuration.credit.microdollars) >
137
+ BigInt(configuration.ceiling.microdollars)) {
138
+ context.addIssue({
139
+ code: z.ZodIssueCode.custom,
140
+ message: "fixed credit cannot exceed its gross payment ceiling",
141
+ path: ["credit"],
142
+ });
143
+ }
144
+ });
145
+ export const billingAutoTopUpPreviewRequestSchema = z
146
+ .object({
147
+ action: z.enum(["enable", "edit", "disable", "resume"]),
148
+ ceiling: positiveExactCentMoneySchema.optional(),
149
+ credit: positiveExactCentMoneySchema.optional(),
150
+ expectedRevision: z.number().int().nonnegative(),
151
+ triggerBelow: positiveExactCentMoneySchema.optional(),
152
+ })
153
+ .strict()
154
+ .superRefine((request, context) => {
155
+ const replacement = request.action === "enable" || request.action === "edit";
156
+ for (const field of ["ceiling", "credit", "triggerBelow"]) {
157
+ if (replacement === (request[field] === undefined)) {
158
+ context.addIssue({
159
+ code: z.ZodIssueCode.custom,
160
+ message: replacement
161
+ ? `${field} is required for a complete ${request.action} preview`
162
+ : `${field} is not accepted for a ${request.action} preview`,
163
+ path: [field],
164
+ });
165
+ }
166
+ }
167
+ });
168
+ export const billingAutoTopUpApplyRequestSchema = z
169
+ .object({
170
+ confirmed: z.literal(true),
171
+ expectedRevision: z.number().int().nonnegative(),
172
+ preview: z.string().min(1).max(128),
173
+ })
174
+ .strict();
175
+ export const billingFundingQuoteRequestSchema = z
176
+ .object({ credit: manualFundingCreditSchema })
177
+ .strict();
178
+ export const billingFundingQuoteSchema = z
179
+ .object({
180
+ credit: manualFundingCreditSchema,
181
+ expectedRevision: z.number().int().nonnegative(),
182
+ expiresAt: timestampSchema,
183
+ gross: z.literal(null),
184
+ quote: z.string().min(1).max(128),
185
+ tax: z.literal(null),
186
+ taxStatus: z.literal("calculated-at-checkout"),
187
+ })
188
+ .strict();
189
+ export const billingPurchaseRequestSchema = z
190
+ .object({
191
+ confirmed: z.literal(true),
192
+ expectedRevision: z.number().int().nonnegative(),
193
+ quote: z.string().min(1).max(128),
194
+ })
195
+ .strict();
196
+ export const billingCeilingUpdateRequestSchema = z
197
+ .object({
198
+ automaticExecutionTopUpCeiling: exactCentMoneySchema.nullable(),
199
+ expectedRevision: z.number().int().nonnegative(),
200
+ })
201
+ .strict();
202
+ const safeBillingUrlSchema = z
203
+ .string()
204
+ .url()
205
+ .max(4096)
206
+ .refine((value) => {
207
+ try {
208
+ const url = new URL(value);
209
+ return (url.protocol === "https:" &&
210
+ [
211
+ "billing.stripe.com",
212
+ "checkout.stripe.com",
213
+ "invoice.stripe.com",
214
+ "pay.stripe.com",
215
+ ].includes(url.hostname) &&
216
+ url.username === "" &&
217
+ url.password === "" &&
218
+ url.port === "");
219
+ }
220
+ catch {
221
+ return false;
222
+ }
223
+ }, "must be a supported provider-hosted HTTPS billing URL");
224
+ const billingPaymentReasonSchema = z
225
+ .string()
226
+ .regex(/^[a-z][a-z0-9-]{0,127}$/u, "must be a bounded reason code");
227
+ export const billingAutoTopUpRuleSchema = z
228
+ .object({
229
+ cooldownUntil: timestampSchema.nullable(),
230
+ desired: billingAutoTopUpConfigurationSchema.nullable(),
231
+ effective: billingAutoTopUpConfigurationSchema.nullable(),
232
+ setupUrl: safeBillingUrlSchema.optional(),
233
+ state: z.enum(["disabled", "payment-method-required", "ready"]),
234
+ suspension: z
235
+ .object({
236
+ at: timestampSchema,
237
+ reason: z.enum(["authentication-required", "payment-failed"]),
238
+ })
239
+ .strict()
240
+ .nullable(),
241
+ })
242
+ .strict()
243
+ .superRefine((rule, context) => {
244
+ if (rule.state === "disabled" && rule.effective !== null) {
245
+ context.addIssue({
246
+ code: z.ZodIssueCode.custom,
247
+ message: "a disabled rule cannot remain effective",
248
+ path: ["effective"],
249
+ });
250
+ }
251
+ if (rule.state === "ready" && rule.effective === null) {
252
+ context.addIssue({
253
+ code: z.ZodIssueCode.custom,
254
+ message: "a ready rule requires effective authority",
255
+ path: ["effective"],
256
+ });
257
+ }
258
+ if (rule.state !== "payment-method-required" &&
259
+ rule.setupUrl !== undefined) {
260
+ context.addIssue({
261
+ code: z.ZodIssueCode.custom,
262
+ message: "a setup URL is only available while payment authority is required",
263
+ path: ["setupUrl"],
264
+ });
265
+ }
266
+ });
267
+ export const billingAutoTopUpPreviewSchema = z
268
+ .object({
269
+ action: z.enum(["enable", "edit", "disable", "resume"]),
270
+ after: billingAutoTopUpConfigurationSchema.nullable(),
271
+ before: billingAutoTopUpConfigurationSchema.nullable(),
272
+ currentPeriod: z
273
+ .object({
274
+ end: timestampSchema,
275
+ pending: nonnegativeExactMoneySchema,
276
+ remaining: nonnegativeExactMoneySchema.nullable(),
277
+ settled: nonnegativeExactMoneySchema,
278
+ start: timestampSchema,
279
+ })
280
+ .strict(),
281
+ expectedRevision: z.number().int().nonnegative(),
282
+ expandsAuthority: z.boolean(),
283
+ expiresAt: timestampSchema,
284
+ preview: z.string().min(1).max(128),
285
+ subscribedProjectFees: nonnegativeExactMoneySchema,
286
+ })
287
+ .strict();
288
+ export const billingPaymentOperationSchema = z
289
+ .object({
290
+ createdAt: timestampSchema,
291
+ credit: exactCentMoneySchema,
292
+ gross: nonnegativeExactMoneySchema.nullable(),
293
+ id: z.string().min(1).max(255),
294
+ kind: z.enum(BILLING_PAYMENT_KINDS),
295
+ paymentUrl: safeBillingUrlSchema.optional(),
296
+ reason: billingPaymentReasonSchema.optional(),
297
+ receiptUrl: safeBillingUrlSchema.optional(),
298
+ state: z.enum(BILLING_PAYMENT_STATES),
299
+ tax: nonnegativeExactMoneySchema.nullable(),
300
+ taxStatus: z.enum(["calculated-at-checkout", "confirmed"]),
301
+ updatedAt: timestampSchema,
302
+ })
303
+ .strict()
304
+ .superRefine((operation, context) => {
305
+ if (operation.taxStatus === "calculated-at-checkout") {
306
+ if (operation.tax !== null || operation.gross !== null) {
307
+ context.addIssue({
308
+ code: z.ZodIssueCode.custom,
309
+ message: "tax and gross stay unknown until provider confirmation",
310
+ path: ["taxStatus"],
311
+ });
312
+ }
313
+ return;
314
+ }
315
+ if (operation.tax === null || operation.gross === null) {
316
+ context.addIssue({
317
+ code: z.ZodIssueCode.custom,
318
+ message: "confirmed tax status requires exact tax and gross amounts",
319
+ path: ["taxStatus"],
320
+ });
321
+ return;
322
+ }
323
+ if (BigInt(operation.gross.microdollars) !==
324
+ BigInt(operation.credit.microdollars) + BigInt(operation.tax.microdollars)) {
325
+ context.addIssue({
326
+ code: z.ZodIssueCode.custom,
327
+ message: "gross must equal execution credit plus confirmed tax",
328
+ path: ["gross"],
329
+ });
330
+ }
331
+ });
332
+ export const billingFundingViewSchema = z
333
+ .object({
334
+ automaticExecutionTopUp: z.object({
335
+ ceiling: exactCentMoneySchema.nullable(),
336
+ currentPeriod: z.object({
337
+ end: timestampSchema,
338
+ pending: nonnegativeExactMoneySchema,
339
+ remaining: nonnegativeExactMoneySchema.nullable(),
340
+ settled: nonnegativeExactMoneySchema,
341
+ start: timestampSchema,
342
+ }),
343
+ rule: billingAutoTopUpRuleSchema,
344
+ revision: z.number().int().nonnegative(),
345
+ }),
346
+ credit: z.object({
347
+ amountOwed: nonnegativeExactMoneySchema,
348
+ available: nonnegativeExactMoneySchema,
349
+ reserved: nonnegativeExactMoneySchema,
350
+ }),
351
+ freshness: z.object({ kind: z.literal("authoritative") }),
352
+ paymentOperations: z.array(billingPaymentOperationSchema).max(25),
353
+ subscribedProjectFees: nonnegativeExactMoneySchema,
354
+ })
355
+ .strict()
356
+ .superRefine((view, context) => {
357
+ const ceiling = view.automaticExecutionTopUp.ceiling;
358
+ const period = view.automaticExecutionTopUp.currentPeriod;
359
+ if (ceiling === null) {
360
+ if (period.remaining !== null) {
361
+ context.addIssue({
362
+ code: z.ZodIssueCode.custom,
363
+ message: "remaining must be null when automatic funding is off",
364
+ path: ["automaticExecutionTopUp", "currentPeriod", "remaining"],
365
+ });
366
+ }
367
+ return;
368
+ }
369
+ const committed = BigInt(period.pending.microdollars) + BigInt(period.settled.microdollars);
370
+ const cap = BigInt(ceiling.microdollars);
371
+ const expected = cap > committed ? cap - committed : 0n;
372
+ if (period.remaining?.microdollars !== expected.toString()) {
373
+ context.addIssue({
374
+ code: z.ZodIssueCode.custom,
375
+ message: "remaining must reflect settled plus pending gross charges",
376
+ path: ["automaticExecutionTopUp", "currentPeriod", "remaining"],
377
+ });
378
+ }
379
+ });
380
+ export const BILLING_NOTICE_KINDS = [
381
+ "budget-warning",
382
+ "budget-exhausted",
383
+ "low-credit",
384
+ "automatic-top-up-cap-reached",
385
+ "funding-blocked",
386
+ "payment-pending",
387
+ "payment-succeeded",
388
+ "payment-failed",
389
+ "payment-authentication-required",
390
+ "payment-outcome-unresolved",
391
+ "service-restored",
392
+ ];
393
+ export const billingNoticeRecoveryPathSchema = z.enum([
394
+ "#billing",
395
+ "#billing-funding",
396
+ "#billing-notification-settings",
397
+ ]);
398
+ export const billingNoticeSchema = z
399
+ .object({
400
+ amounts: z
401
+ .object({
402
+ available: nonnegativeExactMoneySchema.optional(),
403
+ gross: nonnegativeExactMoneySchema.optional(),
404
+ limit: nonnegativeExactMoneySchema.optional(),
405
+ threshold: nonnegativeExactMoneySchema.optional(),
406
+ })
407
+ .strict(),
408
+ detail: z.string().min(1).max(512),
409
+ email: z
410
+ .object({
411
+ attempts: z.number().int().nonnegative().max(100),
412
+ failureCode: billingPaymentReasonSchema.optional(),
413
+ lastAttemptAt: timestampSchema.nullable(),
414
+ state: z.enum(["pending", "delivered", "failed", "suppressed"]),
415
+ })
416
+ .strict(),
417
+ id: z.string().min(1).max(128),
418
+ kind: z.enum(BILLING_NOTICE_KINDS),
419
+ occurredAt: timestampSchema,
420
+ payment: z
421
+ .object({
422
+ operation: z.string().min(1).max(255),
423
+ state: z.enum(BILLING_PAYMENT_STATES),
424
+ })
425
+ .strict()
426
+ .nullable(),
427
+ recoveryPath: billingNoticeRecoveryPathSchema,
428
+ resolvedAt: timestampSchema.nullable(),
429
+ scope: z.discriminatedUnion("kind", [
430
+ z.object({ kind: z.literal("organization") }).strict(),
431
+ z
432
+ .object({ kind: z.literal("project"), project: projectIdSchema })
433
+ .strict(),
434
+ ]),
435
+ severity: z.enum(["warning", "critical", "recovery"]),
436
+ state: z.enum(["active", "resolved"]),
437
+ title: z.string().min(1).max(160),
438
+ updatedAt: timestampSchema,
439
+ })
440
+ .strict()
441
+ .superRefine((notice, context) => {
442
+ if ((notice.state === "resolved") !== (notice.resolvedAt !== null)) {
443
+ context.addIssue({
444
+ code: z.ZodIssueCode.custom,
445
+ message: "resolved notices require resolvedAt and active notices forbid it",
446
+ path: ["resolvedAt"],
447
+ });
448
+ }
449
+ if (notice.email.state === "failed" &&
450
+ notice.email.failureCode === undefined) {
451
+ context.addIssue({
452
+ code: z.ZodIssueCode.custom,
453
+ message: "failed email delivery requires a bounded failure code",
454
+ path: ["email", "failureCode"],
455
+ });
456
+ }
457
+ });
458
+ export const billingNoticePageSchema = pageSchema(billingNoticeSchema).extend({
459
+ freshness: z.object({ kind: z.literal("authoritative") }),
460
+ });
461
+ export const billingNotificationSettingsSchema = z
462
+ .object({
463
+ criticalEmail: z.literal(true),
464
+ freshness: z.object({ kind: z.literal("authoritative") }),
465
+ lowCreditThreshold: exactCentMoneySchema,
466
+ noncriticalEmail: z.boolean(),
467
+ recipients: z
468
+ .object({
469
+ billingContacts: z.literal("active-billing-role-members"),
470
+ owners: z.literal(true),
471
+ })
472
+ .strict(),
473
+ revision: z.number().int().nonnegative(),
474
+ })
475
+ .strict();
476
+ export const billingNotificationSettingsUpdateRequestSchema = z
477
+ .object({
478
+ expectedRevision: z.number().int().nonnegative(),
479
+ lowCreditThreshold: positiveExactCentMoneySchema,
480
+ noncriticalEmail: z.boolean(),
481
+ })
482
+ .strict();
483
+ export const billingRefundRequestCreateSchema = z
484
+ .object({
485
+ amount: positiveExactCentMoneySchema,
486
+ confirmed: z.literal(true),
487
+ paymentOperation: z.string().min(1).max(255),
488
+ reason: z.string().trim().min(1).max(128),
489
+ })
490
+ .strict();
491
+ export const billingRefundResolutionRequestSchema = z
492
+ .object({
493
+ confirmed: z.literal(true),
494
+ decision: z.enum(["completed", "declined"]),
495
+ gross: positiveExactCentMoneySchema.optional(),
496
+ providerRefund: z
497
+ .string()
498
+ .regex(/^re_[A-Za-z0-9_]+$/u, "must be a Stripe refund identifier")
499
+ .max(255)
500
+ .optional(),
501
+ tax: exactCentMoneySchema.optional(),
502
+ })
503
+ .strict()
504
+ .superRefine((request, context) => {
505
+ const completed = request.decision === "completed";
506
+ for (const field of ["gross", "providerRefund", "tax"]) {
507
+ if (completed === (request[field] === undefined)) {
508
+ context.addIssue({
509
+ code: z.ZodIssueCode.custom,
510
+ message: completed
511
+ ? `${field} is required for a completed refund`
512
+ : `${field} is not accepted for a declined refund`,
513
+ path: [field],
514
+ });
515
+ }
516
+ }
517
+ });
518
+ export const billingRefundRequestViewSchema = z
519
+ .object({
520
+ amount: positiveExactCentMoneySchema,
521
+ id: z.string().min(1).max(255),
522
+ paymentOperation: z.string().min(1).max(255),
523
+ requestedAt: timestampSchema,
524
+ state: z.literal("operator-review-pending"),
525
+ })
526
+ .strict();
527
+ export const billingBudgetUpdateRequestSchema = z.object({
528
+ advisoryBudget: exactCentMoneySchema.nullable(),
529
+ expectedRevision: z.number().int().nonnegative(),
530
+ hardCap: exactCentMoneySchema.nullable(),
531
+ });
532
+ const billingBudgetSettingsSchema = z.object({
533
+ advisoryBudget: nonnegativeExactMoneySchema.nullable(),
534
+ hardCap: nonnegativeExactMoneySchema.nullable(),
535
+ });
536
+ export const billingBudgetPolicySchema = z
537
+ .object({
538
+ desired: billingBudgetSettingsSchema,
539
+ desiredRevision: z.number().int().nonnegative(),
540
+ effectiveRevision: z.number().int().nonnegative(),
541
+ pending: z.boolean(),
542
+ })
543
+ .superRefine((policy, context) => {
544
+ if (!policy.pending &&
545
+ policy.desiredRevision !== policy.effectiveRevision) {
546
+ context.addIssue({
547
+ code: z.ZodIssueCode.custom,
548
+ message: "different desired and effective budget revisions must remain pending",
549
+ });
550
+ }
551
+ });
552
+ export const billingPeriodSummarySchema = z.object({
553
+ advisoryBudget: nonnegativeExactMoneySchema.optional(),
554
+ hardCap: nonnegativeExactMoneySchema.optional(),
555
+ remainingToHardCap: nonnegativeExactMoneySchema.optional(),
556
+ advisoryBudgetProgress: z
557
+ .object({
558
+ committed: nonnegativeExactMoneySchema,
559
+ remaining: nonnegativeExactMoneySchema,
560
+ })
561
+ .optional(),
562
+ automaticExecutionTopUp: z.object({
563
+ cap: nonnegativeExactMoneySchema.optional(),
564
+ pending: nonnegativeExactMoneySchema,
565
+ remainingToCap: nonnegativeExactMoneySchema.optional(),
566
+ settled: nonnegativeExactMoneySchema,
567
+ }),
568
+ subscribedProjectFees: nonnegativeExactMoneySchema,
569
+ reservedUsage: nonnegativeExactMoneySchema,
570
+ settledUsage: nonnegativeExactMoneySchema,
571
+ start: timestampSchema,
572
+ end: timestampSchema,
573
+ });
574
+ export const billingSummarySchema = z
575
+ .object({
576
+ activation: z.object({
577
+ boundary: timestampSchema,
578
+ mode: z.enum(BILLING_ACTIVATION_MODES),
579
+ }),
580
+ blockingReasons: z.array(z.enum(BILLING_BLOCK_REASONS)),
581
+ budgetPolicy: billingBudgetPolicySchema,
582
+ closedAt: timestampSchema.optional(),
583
+ credit: z.object({
584
+ available: signedExactMoneySchema,
585
+ consumed: nonnegativeExactMoneySchema,
586
+ reserved: nonnegativeExactMoneySchema,
587
+ }),
588
+ desiredRevision: z.number().int().positive(),
589
+ effectiveRevision: z.number().int().positive(),
590
+ freshness: z.object({ kind: z.literal("authoritative") }),
591
+ includedProject: projectIdSchema.optional(),
592
+ period: billingPeriodSummarySchema.optional(),
593
+ pending: z.boolean(),
594
+ priceVersion: z.string().min(1).max(64),
595
+ trialExpiresAt: timestampSchema.optional(),
596
+ })
597
+ .superRefine((summary, context) => {
598
+ if (!summary.pending &&
599
+ summary.desiredRevision !== summary.effectiveRevision) {
600
+ context.addIssue({
601
+ code: z.ZodIssueCode.custom,
602
+ message: "different desired and effective revisions must remain pending",
603
+ });
604
+ }
605
+ });
606
+ export const billingBudgetUpdateResponseSchema = z.object({
607
+ budgetPolicy: billingBudgetPolicySchema,
608
+ freshness: z.object({ kind: z.literal("authoritative") }),
609
+ });
610
+ export const billingBudgetUpdateRequestHeadersSchema = requiredIdempotencyRequestHeaderSchema;
611
+ export const billingLedgerEntrySchema = z.object({
612
+ amount: z.object({
613
+ currency: z.literal(BILLING_CURRENCY),
614
+ microdollars: microdollarAmountSchema,
615
+ scale: z.literal(BILLING_AMOUNT_SCALE),
616
+ }),
617
+ kind: z.enum(BILLING_ENTRY_KINDS),
618
+ period: timestampSchema.optional(),
619
+ recordedAt: timestampSchema,
620
+ reference: z.object({
621
+ attempt: attemptIdSchema.optional(),
622
+ creditLot: z.string().min(1).max(128).optional(),
623
+ event: z.string().min(1).max(255),
624
+ paymentOperation: z.string().min(1).max(255).optional(),
625
+ }),
626
+ sequence: nonnegativeMicrodollarAmountSchema.refine((value) => value !== "0", "must be positive"),
627
+ });
628
+ export const billingLedgerRequestSchema = pageRequestSchema;
629
+ export const billingLedgerPageSchema = pageSchema(billingLedgerEntrySchema).extend({
630
+ freshness: z.object({ kind: z.literal("authoritative") }),
631
+ });
632
+ export const PROJECT_BILLING_ACTIONS = [
633
+ "add",
634
+ "cancel",
635
+ "transfer-included",
636
+ ];
637
+ export const projectBillingQuoteRequestSchema = z
638
+ .object({
639
+ action: z.enum(PROJECT_BILLING_ACTIONS),
640
+ project: projectIdSchema,
641
+ fromProject: projectIdSchema.optional(),
642
+ })
643
+ .strict();
644
+ export const projectBillingQuoteSchema = projectBillingQuoteRequestSchema.extend({
645
+ quote: z.string().min(1).max(128),
646
+ expectedRevision: z.number().int().nonnegative(),
647
+ expiresAt: timestampSchema,
648
+ charge: nonnegativeExactMoneySchema,
649
+ monthlyProjectFees: nonnegativeExactMoneySchema,
650
+ effectiveAt: timestampSchema,
651
+ formerIncludedWillBlock: z.boolean(),
652
+ });
653
+ export const projectBillingChangeRequestSchema = z
654
+ .object({
655
+ quote: z.string().min(1).max(128),
656
+ expectedRevision: z.number().int().nonnegative(),
657
+ confirmed: z.literal(true),
658
+ })
659
+ .strict();
660
+ export const projectBillingStateSchema = z.object({
661
+ includedProject: projectIdSchema.optional(),
662
+ desiredRevision: z.number().int().positive(),
663
+ effectiveRevision: z.number().int().nonnegative(),
664
+ pending: z.boolean(),
665
+ recurringProjectFees: nonnegativeExactMoneySchema,
666
+ projects: z.array(z.object({
667
+ name: z.string(),
668
+ project: projectIdSchema,
669
+ access: z.enum(["included", "paid", "blocked"]),
670
+ paidThroughAt: timestampSchema.optional(),
671
+ renewalGraceUntil: timestampSchema.optional(),
672
+ cancellationAt: timestampSchema.optional(),
673
+ deleted: z.boolean(),
674
+ })),
675
+ pendingOperations: z.array(z.object({
676
+ id: z.string().min(1).max(255),
677
+ kind: z.enum(["add", "cancel"]),
678
+ project: projectIdSchema,
679
+ state: z.enum(["pending", "action-required"]),
680
+ paymentUrl: z.string().url().optional(),
681
+ reason: z.string().min(1).max(128).optional(),
682
+ })),
683
+ });
684
+ export const billingPortalSchema = z.object({ url: z.string().url() });
@@ -4,8 +4,8 @@
4
4
  * DNS is deliberately not represented here: names are resolved and every
5
5
  * returned address is passed through `isPublicCallbackAddress` by the caller.
6
6
  *
7
- * **That caller is endpoint creation and verification, and since 2026-08-11 it
8
- * is nowhere else.** This comment used to end "and immediately before a send",
7
+ * **That caller is endpoint creation and update, and since 2026-08-11 it is
8
+ * nowhere else.** This comment used to end "and immediately before a send",
9
9
  * which FXO-1566 made false when it removed the send-time re-resolution. What
10
10
  * runs at send time is `evaluateCallbackUrl` alone — a string check, which
11
11
  * cannot see where a hostname points now. FXO-1575 measured what the platform