@greatwait/contracts 0.1.0-alpha.3 → 0.1.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -10
- package/dist/authority.d.ts +33 -27
- package/dist/authority.js +12 -2
- package/dist/billing.d.ts +1231 -0
- package/dist/billing.js +833 -0
- package/dist/callback-safety.d.ts +2 -2
- package/dist/callback-safety.js +15 -5
- package/dist/compatibility.d.ts +3 -3
- package/dist/compatibility.js +1 -1
- package/dist/configuration-bounds.d.ts +13 -0
- package/dist/configuration-bounds.js +13 -0
- package/dist/data-export.d.ts +67 -0
- package/dist/data-export.js +182 -0
- package/dist/effective-limits.d.ts +40 -0
- package/dist/effective-limits.js +42 -0
- package/dist/endpoints.d.ts +186 -245
- package/dist/endpoints.js +82 -86
- package/dist/events.d.ts +17 -17
- package/dist/events.js +1 -1
- package/dist/first-value-journey.d.ts +50 -56
- package/dist/first-value-journey.js +17 -20
- package/dist/forecast.d.ts +182 -92
- package/dist/forecast.js +88 -25
- package/dist/identifiers.d.ts +20 -20
- package/dist/identifiers.js +1 -1
- package/dist/identity.d.ts +41 -37
- package/dist/identity.js +5 -4
- package/dist/index.d.ts +12 -6
- package/dist/index.js +12 -6
- package/dist/mcp.d.ts +21 -19
- package/dist/mcp.js +2 -2
- package/dist/naming.d.ts +45 -0
- package/dist/naming.js +159 -0
- package/dist/oauth.d.ts +186 -172
- package/dist/oauth.js +1 -1
- package/dist/operation-definitions.d.ts +9 -0
- package/dist/operation-definitions.js +7 -0
- package/dist/operational-config.d.ts +101 -0
- package/dist/operational-config.js +341 -0
- package/dist/operations.d.ts +4742 -2170
- package/dist/operations.js +3064 -932
- package/dist/organization-lifecycle.d.ts +34 -0
- package/dist/organization-lifecycle.js +122 -0
- package/dist/partition.d.ts +43 -9
- package/dist/partition.js +3 -3
- package/dist/policy.d.ts +4 -4
- package/dist/policy.js +9 -5
- package/dist/problems.d.ts +57 -28
- package/dist/problems.js +55 -3
- package/dist/protocol.d.ts +209 -80
- package/dist/protocol.js +110 -37
- package/dist/scheduling-records.d.ts +349 -285
- package/dist/scheduling-records.js +1 -1
- package/dist/scheduling.d.ts +707 -361
- package/dist/scheduling.js +443 -61
- package/dist/secrets.d.ts +119 -105
- package/dist/secrets.js +1 -1
- package/dist/signatures.d.ts +74 -74
- package/dist/signatures.js +1 -1
- package/dist/tenancy.d.ts +142 -68
- package/dist/tenancy.js +70 -17
- package/dist/test-sink.d.ts +127 -127
- package/dist/test-sink.js +1 -1
- package/dist/time.d.ts +4 -4
- package/dist/time.js +1 -1
- package/dist/timing.d.ts +65 -0
- package/dist/timing.js +82 -0
- package/dist/usage.d.ts +103 -47
- package/dist/usage.js +183 -32
- package/dist/workspace.d.ts +34 -34
- package/dist/workspace.js +1 -1
- package/dist/zod-values.d.ts +3 -0
- package/dist/zod-values.js +2 -0
- package/dist/zod.d.ts +2 -0
- package/dist/zod.js +2 -0
- package/generated/v1/examples/attempts.list.response.json +6 -0
- package/generated/v1/examples/attempts.read.response.json +6 -0
- package/generated/v1/examples/billing.autotopup.request.json +5 -0
- package/generated/v1/examples/billing.autotopup.response.json +120 -0
- package/generated/v1/examples/billing.autotopuppreview.request.json +19 -0
- package/generated/v1/examples/billing.autotopuppreview.response.json +45 -0
- package/generated/v1/examples/billing.budgets.request.json +13 -0
- package/generated/v1/examples/billing.budgets.response.json +22 -0
- package/generated/v1/examples/billing.ceiling.request.json +8 -0
- package/generated/v1/examples/billing.ceiling.response.json +120 -0
- package/generated/v1/examples/billing.change.request.json +5 -0
- package/generated/v1/examples/billing.change.response.json +12 -0
- package/generated/v1/examples/billing.funding.response.json +120 -0
- package/generated/v1/examples/billing.fundingconfirm.response.json +120 -0
- package/generated/v1/examples/billing.fundingquote.request.json +7 -0
- package/generated/v1/examples/billing.fundingquote.response.json +13 -0
- package/generated/v1/examples/billing.invoicehistory.response.json +6 -0
- package/generated/v1/examples/billing.invoices.response.json +15 -0
- package/generated/v1/examples/billing.ledger.response.json +23 -0
- package/generated/v1/examples/billing.notices.response.json +41 -0
- package/generated/v1/examples/billing.notificationsettings.response.json +17 -0
- package/generated/v1/examples/billing.notificationsettingsupdate.request.json +9 -0
- package/generated/v1/examples/billing.notificationsettingsupdate.response.json +17 -0
- package/generated/v1/examples/billing.paymenthistory.response.json +6 -0
- package/generated/v1/examples/billing.paymentmethod.response.json +16 -0
- package/generated/v1/examples/billing.paymentmethodconfirm.request.json +3 -0
- package/generated/v1/examples/billing.paymentmethodconfirm.response.json +16 -0
- package/generated/v1/examples/billing.paymentmethodremove.request.json +3 -0
- package/generated/v1/examples/billing.paymentmethodremove.response.json +4 -0
- package/generated/v1/examples/billing.paymentmethodsetup.request.json +1 -0
- package/generated/v1/examples/billing.paymentmethodsetup.response.json +3 -0
- package/generated/v1/examples/billing.portal.response.json +3 -0
- package/generated/v1/examples/billing.projects.response.json +12 -0
- package/generated/v1/examples/billing.purchase.request.json +5 -0
- package/generated/v1/examples/billing.purchase.response.json +120 -0
- package/generated/v1/examples/billing.quote.request.json +4 -0
- package/generated/v1/examples/billing.quote.response.json +19 -0
- package/generated/v1/examples/billing.reconcile.response.json +73 -0
- package/generated/v1/examples/billing.refundrequest.request.json +10 -0
- package/generated/v1/examples/billing.refundrequest.response.json +11 -0
- package/generated/v1/examples/billing.refundresolution.request.json +4 -0
- package/generated/v1/examples/billing.refundresolution.response.json +120 -0
- package/generated/v1/examples/billing.summary.response.json +73 -0
- package/generated/v1/examples/endpoints.acknowledgeSigningKeyRotation.response.json +18 -0
- package/generated/v1/examples/endpoints.create.response.json +1 -1
- package/generated/v1/examples/endpoints.disable.response.json +0 -1
- package/generated/v1/examples/{endpoints.verify.response.json → endpoints.enable.response.json} +4 -5
- package/generated/v1/examples/endpoints.list.response.json +1 -2
- package/generated/v1/examples/endpoints.read.response.json +2 -2
- package/generated/v1/examples/endpoints.revealSigningSecret.response.json +7 -0
- package/generated/v1/examples/endpoints.rotateSigningKey.response.json +1 -2
- package/generated/v1/examples/endpoints.update.response.json +1 -1
- package/generated/v1/examples/executions.list.response.json +20 -0
- package/generated/v1/examples/exports.cancel.response.json +11 -0
- package/generated/v1/examples/exports.create.request.json +1 -0
- package/generated/v1/examples/exports.create.response.json +8 -0
- package/generated/v1/examples/exports.part.response.json +5 -0
- package/generated/v1/examples/exports.read.response.json +8 -0
- package/generated/v1/examples/limits.read.response.json +16 -0
- package/generated/v1/examples/occurrences.read.response.json +4 -0
- package/generated/v1/examples/occurrences.redeliver.response.json +2 -0
- package/generated/v1/examples/organizations.close.request.json +5 -0
- package/generated/v1/examples/organizations.close.response.json +10 -0
- package/generated/v1/examples/organizations.lifecycle.response.json +10 -0
- package/generated/v1/examples/organizations.restore.request.json +3 -0
- package/generated/v1/examples/organizations.restore.response.json +10 -0
- package/generated/v1/examples/projects.archive.request.json +3 -0
- package/generated/v1/examples/projects.archive.response.json +14 -0
- package/generated/v1/examples/projects.create.response.json +10 -1
- package/generated/v1/examples/projects.delete.response.json +9 -0
- package/generated/v1/examples/projects.list.response.json +12 -2
- package/generated/v1/examples/projects.rename.request.json +3 -0
- package/generated/v1/examples/projects.rename.response.json +14 -0
- package/generated/v1/examples/schedules.archive.response.json +3 -0
- package/generated/v1/examples/schedules.cancel.response.json +3 -0
- package/generated/v1/examples/schedules.create.request.json +4 -0
- package/generated/v1/examples/schedules.create.response.json +3 -0
- package/generated/v1/examples/schedules.list.response.json +3 -0
- package/generated/v1/examples/schedules.pause.response.json +3 -0
- package/generated/v1/examples/schedules.read.response.json +6 -0
- package/generated/v1/examples/schedules.replace.request.json +4 -0
- package/generated/v1/examples/schedules.replace.response.json +3 -0
- package/generated/v1/examples/schedules.resume.response.json +3 -0
- package/generated/v1/examples/timing.summary.response.json +35 -0
- package/generated/v1/examples/usage.read.response.json +1 -0
- package/generated/v1/first-value-journey.json +43 -18
- package/generated/v1/manifest.json +1287 -42
- package/generated/v1/openapi.json +36033 -5982
- package/generated/v1/policy-matrix.json +341 -47
- package/generated/v1/schemas/attempts.list.response.json +39 -1
- package/generated/v1/schemas/attempts.read.response.json +39 -1
- package/generated/v1/schemas/billing.autotopup.request-headers.json +13 -0
- package/generated/v1/schemas/billing.autotopup.request.json +22 -0
- package/generated/v1/schemas/billing.autotopup.response-headers.json +10 -0
- package/generated/v1/schemas/billing.autotopup.response.json +552 -0
- package/generated/v1/schemas/billing.autotopuppreview.request.json +77 -0
- package/generated/v1/schemas/billing.autotopuppreview.response.json +277 -0
- package/generated/v1/schemas/billing.budgets.request-headers.json +13 -0
- package/generated/v1/schemas/billing.budgets.request.json +66 -0
- package/generated/v1/schemas/billing.budgets.response-headers.json +10 -0
- package/generated/v1/schemas/billing.budgets.response.json +92 -0
- package/generated/v1/schemas/billing.ceiling.request-headers.json +13 -0
- package/generated/v1/schemas/billing.ceiling.request.json +40 -0
- package/generated/v1/schemas/billing.ceiling.response-headers.json +10 -0
- package/generated/v1/schemas/billing.ceiling.response.json +552 -0
- package/generated/v1/schemas/billing.change.request-headers.json +13 -0
- package/generated/v1/schemas/billing.change.request.json +22 -0
- package/generated/v1/schemas/billing.change.response.json +119 -0
- package/generated/v1/schemas/billing.funding.response.json +552 -0
- package/generated/v1/schemas/billing.fundingconfirm.response.json +552 -0
- package/generated/v1/schemas/billing.fundingquote.request.json +28 -0
- package/generated/v1/schemas/billing.fundingquote.response.json +61 -0
- package/generated/v1/schemas/billing.invoicehistory.query.json +16 -0
- package/generated/v1/schemas/billing.invoicehistory.response.json +88 -0
- package/generated/v1/schemas/billing.invoices.response.json +51 -0
- package/generated/v1/schemas/billing.ledger.query.json +16 -0
- package/generated/v1/schemas/billing.ledger.response.json +130 -0
- package/generated/v1/schemas/billing.notices.query.json +16 -0
- package/generated/v1/schemas/billing.notices.response.json +278 -0
- package/generated/v1/schemas/billing.notificationsettings.response.json +70 -0
- package/generated/v1/schemas/billing.notificationsettingsupdate.request-headers.json +13 -0
- package/generated/v1/schemas/billing.notificationsettingsupdate.request.json +43 -0
- package/generated/v1/schemas/billing.notificationsettingsupdate.response-headers.json +10 -0
- package/generated/v1/schemas/billing.notificationsettingsupdate.response.json +70 -0
- package/generated/v1/schemas/billing.paymenthistory.query.json +16 -0
- package/generated/v1/schemas/billing.paymenthistory.response.json +182 -0
- package/generated/v1/schemas/billing.paymentmethod.response.json +137 -0
- package/generated/v1/schemas/billing.paymentmethodconfirm.request.json +14 -0
- package/generated/v1/schemas/billing.paymentmethodconfirm.response.json +137 -0
- package/generated/v1/schemas/billing.paymentmethodremove.request.json +12 -0
- package/generated/v1/schemas/billing.paymentmethodremove.response.json +137 -0
- package/generated/v1/schemas/billing.paymentmethodsetup.request.json +12 -0
- package/generated/v1/schemas/billing.paymentmethodsetup.response.json +11 -0
- package/generated/v1/schemas/billing.portal.response.json +11 -0
- package/generated/v1/schemas/billing.projects.response.json +119 -0
- package/generated/v1/schemas/billing.purchase.request-headers.json +13 -0
- package/generated/v1/schemas/billing.purchase.request.json +26 -0
- package/generated/v1/schemas/billing.purchase.response-headers.json +10 -0
- package/generated/v1/schemas/billing.purchase.response.json +552 -0
- package/generated/v1/schemas/billing.quote.request.json +20 -0
- package/generated/v1/schemas/billing.quote.response.json +86 -0
- package/generated/v1/schemas/billing.reconcile.response.json +468 -0
- package/generated/v1/schemas/billing.refundrequest.request-headers.json +13 -0
- package/generated/v1/schemas/billing.refundrequest.request.json +42 -0
- package/generated/v1/schemas/billing.refundrequest.response-headers.json +10 -0
- package/generated/v1/schemas/billing.refundrequest.response.json +45 -0
- package/generated/v1/schemas/billing.refundresolution.request-headers.json +13 -0
- package/generated/v1/schemas/billing.refundresolution.request.json +61 -0
- package/generated/v1/schemas/billing.refundresolution.response-headers.json +10 -0
- package/generated/v1/schemas/billing.refundresolution.response.json +552 -0
- package/generated/v1/schemas/billing.summary.response.json +468 -0
- package/generated/v1/schemas/context.read.response.json +2 -0
- package/generated/v1/schemas/credentials.connection.response.json +2 -0
- package/generated/v1/schemas/credentials.create.request.json +2 -0
- package/generated/v1/schemas/credentials.create.response.json +2 -0
- package/generated/v1/schemas/credentials.list.response.json +2 -0
- package/generated/v1/schemas/credentials.revoke.response.json +2 -0
- package/generated/v1/schemas/credentials.rotate.response.json +4 -0
- package/generated/v1/schemas/{endpoints.verify.request-headers.json → endpoints.acknowledgeSigningKeyRotation.request-headers.json} +2 -1
- package/generated/v1/schemas/{endpoints.verify.response.json → endpoints.acknowledgeSigningKeyRotation.response.json} +8 -21
- package/generated/v1/schemas/endpoints.create.request.json +5 -0
- package/generated/v1/schemas/endpoints.create.response.json +8 -21
- package/generated/v1/schemas/endpoints.disable.response.json +8 -21
- package/generated/v1/schemas/endpoints.enable.response-headers.json +11 -0
- package/generated/v1/schemas/endpoints.enable.response.json +87 -0
- package/generated/v1/schemas/endpoints.list.response.json +8 -21
- package/generated/v1/schemas/endpoints.read.response.json +8 -21
- package/generated/v1/schemas/endpoints.revealSigningSecret.response.json +43 -0
- package/generated/v1/schemas/endpoints.rotateSigningKey.response.json +8 -21
- package/generated/v1/schemas/endpoints.update.request.json +5 -0
- package/generated/v1/schemas/endpoints.update.response.json +8 -21
- package/generated/v1/schemas/executions.list.query.json +46 -0
- package/generated/v1/schemas/executions.list.response.json +116 -0
- package/generated/v1/schemas/exports.cancel.response.json +48 -0
- package/generated/v1/schemas/exports.create.request.json +6 -0
- package/generated/v1/schemas/exports.create.response.json +38 -0
- package/generated/v1/schemas/exports.part.query.json +11 -0
- package/generated/v1/schemas/exports.part.response.json +22 -0
- package/generated/v1/schemas/exports.read.response.json +38 -0
- package/generated/v1/schemas/forecast.read.request-headers.json +10 -0
- package/generated/v1/schemas/forecast.read.response.json +148 -0
- package/generated/v1/schemas/grants.list.response.json +2 -0
- package/generated/v1/schemas/grants.revoke.response.json +2 -0
- package/generated/v1/schemas/limits.read.response.json +79 -0
- package/generated/v1/schemas/occurrences.list.query.json +5 -0
- package/generated/v1/schemas/occurrences.list.response.json +23 -0
- package/generated/v1/schemas/occurrences.read.response.json +23 -0
- package/generated/v1/schemas/occurrences.redeliver.response.json +39 -1
- package/generated/v1/schemas/organizations.close.request.json +20 -0
- package/generated/v1/schemas/organizations.close.response.json +68 -0
- package/generated/v1/schemas/organizations.lifecycle.response.json +68 -0
- package/generated/v1/schemas/organizations.restore.request.json +13 -0
- package/generated/v1/schemas/organizations.restore.response.json +68 -0
- package/generated/v1/schemas/projects.archive.request-headers.json +11 -0
- package/generated/v1/schemas/projects.archive.request.json +10 -0
- package/generated/v1/schemas/projects.archive.response-headers.json +11 -0
- package/generated/v1/schemas/projects.archive.response.json +79 -0
- package/generated/v1/schemas/projects.create.response.json +55 -1
- package/generated/v1/schemas/projects.delete.request-headers.json +11 -0
- package/generated/v1/schemas/projects.delete.response.json +37 -0
- package/generated/v1/schemas/projects.list.response.json +61 -2
- package/generated/v1/schemas/projects.rename.request-headers.json +11 -0
- package/generated/v1/schemas/projects.rename.request.json +12 -0
- package/generated/v1/schemas/projects.rename.response-headers.json +11 -0
- package/generated/v1/schemas/projects.rename.response.json +79 -0
- package/generated/v1/schemas/schedules.archive.response.json +90 -2
- package/generated/v1/schemas/schedules.cancel.response.json +90 -2
- package/generated/v1/schemas/schedules.create.request.json +24 -3
- package/generated/v1/schemas/schedules.create.response.json +90 -2
- package/generated/v1/schemas/schedules.list.query.json +13 -0
- package/generated/v1/schemas/schedules.list.response.json +67 -2
- package/generated/v1/schemas/schedules.pause.response.json +90 -2
- package/generated/v1/schemas/schedules.read.response.json +90 -2
- package/generated/v1/schemas/schedules.replace.request.json +24 -3
- package/generated/v1/schemas/schedules.replace.response.json +90 -2
- package/generated/v1/schemas/schedules.resume.response.json +90 -2
- package/generated/v1/schemas/timing.summary.response.json +191 -0
- package/generated/v1/schemas/usage.read.query.json +7 -0
- package/generated/v1/schemas/usage.read.response.json +36 -1
- package/generated/v1/snippets/billing.autotopup.json +6 -0
- package/generated/v1/snippets/billing.autotopuppreview.json +6 -0
- package/generated/v1/snippets/billing.budgets.json +6 -0
- package/generated/v1/snippets/billing.ceiling.json +6 -0
- package/generated/v1/snippets/billing.change.json +6 -0
- package/generated/v1/snippets/billing.funding.json +6 -0
- package/generated/v1/snippets/billing.fundingconfirm.json +6 -0
- package/generated/v1/snippets/billing.fundingquote.json +6 -0
- package/generated/v1/snippets/billing.invoicehistory.json +6 -0
- package/generated/v1/snippets/billing.invoices.json +6 -0
- package/generated/v1/snippets/billing.ledger.json +6 -0
- package/generated/v1/snippets/billing.notices.json +6 -0
- package/generated/v1/snippets/billing.notificationsettings.json +6 -0
- package/generated/v1/snippets/billing.notificationsettingsupdate.json +6 -0
- package/generated/v1/snippets/billing.paymenthistory.json +6 -0
- package/generated/v1/snippets/billing.paymentmethod.json +6 -0
- package/generated/v1/snippets/billing.paymentmethodconfirm.json +6 -0
- package/generated/v1/snippets/billing.paymentmethodremove.json +6 -0
- package/generated/v1/snippets/billing.paymentmethodsetup.json +6 -0
- package/generated/v1/snippets/billing.portal.json +6 -0
- package/generated/v1/snippets/billing.projects.json +6 -0
- package/generated/v1/snippets/billing.purchase.json +6 -0
- package/generated/v1/snippets/billing.quote.json +6 -0
- package/generated/v1/snippets/billing.reconcile.json +6 -0
- package/generated/v1/snippets/billing.refundrequest.json +6 -0
- package/generated/v1/snippets/billing.refundresolution.json +6 -0
- package/generated/v1/snippets/billing.summary.json +6 -0
- package/generated/v1/snippets/endpoints.acknowledgeSigningKeyRotation.json +6 -0
- package/generated/v1/snippets/{endpoints.verify.json → endpoints.enable.json} +3 -3
- package/generated/v1/snippets/endpoints.revealSigningSecret.json +6 -0
- package/generated/v1/snippets/executions.list.json +6 -0
- package/generated/v1/snippets/exports.cancel.json +6 -0
- package/generated/v1/snippets/exports.create.json +6 -0
- package/generated/v1/snippets/exports.part.json +6 -0
- package/generated/v1/snippets/exports.read.json +6 -0
- package/generated/v1/snippets/forecast.windows.json +1 -1
- package/generated/v1/snippets/limits.read.json +6 -0
- package/generated/v1/snippets/organizations.close.json +6 -0
- package/generated/v1/snippets/organizations.lifecycle.json +6 -0
- package/generated/v1/snippets/organizations.restore.json +6 -0
- package/generated/v1/snippets/projects.archive.json +6 -0
- package/generated/v1/snippets/projects.delete.json +6 -0
- package/generated/v1/snippets/projects.rename.json +6 -0
- package/generated/v1/snippets/schedules.create.json +3 -3
- package/generated/v1/snippets/schedules.replace.json +3 -3
- package/generated/v1/snippets/timing.summary.json +6 -0
- package/package.json +7 -7
- package/dist/callback-ownership.d.ts +0 -58
- package/dist/callback-ownership.js +0 -71
- package/generated/v1/callback-endpoint-verification.json +0 -59
- /package/generated/v1/schemas/{endpoints.verify.response-headers.json → endpoints.acknowledgeSigningKeyRotation.response-headers.json} +0 -0
package/dist/billing.js
ADDED
|
@@ -0,0 +1,833 @@
|
|
|
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
|
+
/**
|
|
69
|
+
* Why a ledger entry that looks like money moved none.
|
|
70
|
+
*
|
|
71
|
+
* `provider-details-attached`: the payment provider reported details of a
|
|
72
|
+
* payment the ledger already recorded — its charge, receipt, hosted page or
|
|
73
|
+
* tax. The entry repeats the payment's kind and shows a zero amount, so one
|
|
74
|
+
* purchase never reads as two.
|
|
75
|
+
*/
|
|
76
|
+
export const BILLING_LEDGER_ENTRY_NOTES = [
|
|
77
|
+
"provider-details-attached",
|
|
78
|
+
];
|
|
79
|
+
export const BILLING_PAYMENT_KINDS = ["manual", "automatic"];
|
|
80
|
+
export const BILLING_PAYMENT_STATES = [
|
|
81
|
+
"pending",
|
|
82
|
+
"paid",
|
|
83
|
+
"failed",
|
|
84
|
+
"authentication-required",
|
|
85
|
+
"action-required",
|
|
86
|
+
"canceled",
|
|
87
|
+
"refunded",
|
|
88
|
+
"reversed",
|
|
89
|
+
"disputed",
|
|
90
|
+
];
|
|
91
|
+
const signedExactMoneySchema = z.object({
|
|
92
|
+
currency: z.literal(BILLING_CURRENCY),
|
|
93
|
+
microdollars: microdollarAmountSchema,
|
|
94
|
+
scale: z.literal(BILLING_AMOUNT_SCALE),
|
|
95
|
+
});
|
|
96
|
+
const nonnegativeExactMoneySchema = z.object({
|
|
97
|
+
currency: z.literal(BILLING_CURRENCY),
|
|
98
|
+
microdollars: nonnegativeMicrodollarAmountSchema,
|
|
99
|
+
scale: z.literal(BILLING_AMOUNT_SCALE),
|
|
100
|
+
});
|
|
101
|
+
/**
|
|
102
|
+
* The generated request contract for a whole-cent PostgreSQL `bigint`.
|
|
103
|
+
*
|
|
104
|
+
* Zod refinements deliberately remain the runtime authority below, while this
|
|
105
|
+
* JSON Schema metadata gives OpenAPI and MCP validators the same boundary. The
|
|
106
|
+
* long final branch is the inclusive 15-digit cent maximum
|
|
107
|
+
* `922337203685477`, followed by the four zero microdollar places.
|
|
108
|
+
*/
|
|
109
|
+
const exactCentMicrodollarAmountSchema = nonnegativeMicrodollarAmountSchema.meta({
|
|
110
|
+
description: "A canonical nonnegative integer multiple of 10,000 microdollars, no greater than 9,223,372,036,854,770,000.",
|
|
111
|
+
maxLength: 19,
|
|
112
|
+
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)$",
|
|
113
|
+
});
|
|
114
|
+
export const exactCentMoneySchema = z
|
|
115
|
+
.object({
|
|
116
|
+
currency: z.literal(BILLING_CURRENCY),
|
|
117
|
+
microdollars: exactCentMicrodollarAmountSchema,
|
|
118
|
+
scale: z.literal(BILLING_AMOUNT_SCALE),
|
|
119
|
+
})
|
|
120
|
+
.superRefine((amount, context) => {
|
|
121
|
+
const microdollars = BigInt(amount.microdollars);
|
|
122
|
+
if (microdollars % 10000n !== 0n) {
|
|
123
|
+
context.addIssue({
|
|
124
|
+
code: z.ZodIssueCode.custom,
|
|
125
|
+
message: "must be a whole number of cents (10,000 microdollars)",
|
|
126
|
+
path: ["microdollars"],
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (microdollars > 9223372036854770000n) {
|
|
130
|
+
context.addIssue({
|
|
131
|
+
code: z.ZodIssueCode.custom,
|
|
132
|
+
message: "must fit the exact PostgreSQL billing range",
|
|
133
|
+
path: ["microdollars"],
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
export const manualFundingCreditSchema = exactCentMoneySchema.refine((amount) => BigInt(amount.microdollars) >= 10000000n, "manual execution-credit purchases must be at least USD 10");
|
|
138
|
+
const positiveExactCentMoneySchema = exactCentMoneySchema.refine((amount) => BigInt(amount.microdollars) > 0n, "must be greater than zero");
|
|
139
|
+
export const billingAutoTopUpConfigurationSchema = z
|
|
140
|
+
.object({
|
|
141
|
+
ceiling: positiveExactCentMoneySchema,
|
|
142
|
+
credit: positiveExactCentMoneySchema,
|
|
143
|
+
triggerBelow: positiveExactCentMoneySchema,
|
|
144
|
+
})
|
|
145
|
+
.strict()
|
|
146
|
+
.superRefine((configuration, context) => {
|
|
147
|
+
if (BigInt(configuration.credit.microdollars) >
|
|
148
|
+
BigInt(configuration.ceiling.microdollars)) {
|
|
149
|
+
context.addIssue({
|
|
150
|
+
code: z.ZodIssueCode.custom,
|
|
151
|
+
message: "fixed credit cannot exceed its gross payment ceiling",
|
|
152
|
+
path: ["credit"],
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
export const billingAutoTopUpPreviewRequestSchema = z
|
|
157
|
+
.object({
|
|
158
|
+
action: z.enum(["enable", "edit", "disable", "resume"]),
|
|
159
|
+
ceiling: positiveExactCentMoneySchema.optional(),
|
|
160
|
+
credit: positiveExactCentMoneySchema.optional(),
|
|
161
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
162
|
+
triggerBelow: positiveExactCentMoneySchema.optional(),
|
|
163
|
+
})
|
|
164
|
+
.strict()
|
|
165
|
+
.superRefine((request, context) => {
|
|
166
|
+
const replacement = request.action === "enable" || request.action === "edit";
|
|
167
|
+
for (const field of ["ceiling", "credit", "triggerBelow"]) {
|
|
168
|
+
if (replacement === (request[field] === undefined)) {
|
|
169
|
+
context.addIssue({
|
|
170
|
+
code: z.ZodIssueCode.custom,
|
|
171
|
+
message: replacement
|
|
172
|
+
? `${field} is required for a complete ${request.action} preview`
|
|
173
|
+
: `${field} is not accepted for a ${request.action} preview`,
|
|
174
|
+
path: [field],
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
export const billingAutoTopUpApplyRequestSchema = z
|
|
180
|
+
.object({
|
|
181
|
+
confirmed: z.literal(true),
|
|
182
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
183
|
+
preview: z.string().min(1).max(128),
|
|
184
|
+
})
|
|
185
|
+
.strict();
|
|
186
|
+
export const billingFundingQuoteRequestSchema = z
|
|
187
|
+
.object({ credit: manualFundingCreditSchema })
|
|
188
|
+
.strict();
|
|
189
|
+
export const billingFundingQuoteSchema = z
|
|
190
|
+
.object({
|
|
191
|
+
credit: manualFundingCreditSchema,
|
|
192
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
193
|
+
expiresAt: timestampSchema,
|
|
194
|
+
gross: z.literal(null),
|
|
195
|
+
quote: z.string().min(1).max(128),
|
|
196
|
+
tax: z.literal(null),
|
|
197
|
+
taxStatus: z.literal("calculated-at-checkout"),
|
|
198
|
+
})
|
|
199
|
+
.strict();
|
|
200
|
+
export const billingPurchaseRequestSchema = z
|
|
201
|
+
.object({
|
|
202
|
+
automaticTopUp: z
|
|
203
|
+
.boolean()
|
|
204
|
+
.meta({
|
|
205
|
+
description: "true: the customer also asks to top up automatically when credit runs low. The hosted payment then saves the payment method for later off-session charges (it offers every method the account enables except Klarna, which cannot be charged that way), and once the provider confirms this payment paid, automatic top-up is enabled with the default rule (add USD 10.00 when available credit falls below USD 2.00, at most USD 50.00 of automatic charges a month) using that payment method. A rule that is already ready is left unchanged; an enabled rule waiting for a payment method keeps its own amounts and gains this one. Omitted or false: the purchase does exactly what it always did. An unpaid, expired or cancelled payment enables nothing.",
|
|
206
|
+
})
|
|
207
|
+
.optional(),
|
|
208
|
+
confirmed: z.literal(true),
|
|
209
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
210
|
+
quote: z.string().min(1).max(128),
|
|
211
|
+
})
|
|
212
|
+
.strict();
|
|
213
|
+
export const billingCeilingUpdateRequestSchema = z
|
|
214
|
+
.object({
|
|
215
|
+
automaticExecutionTopUpCeiling: exactCentMoneySchema.nullable(),
|
|
216
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
217
|
+
})
|
|
218
|
+
.strict();
|
|
219
|
+
const safeBillingUrlSchema = z
|
|
220
|
+
.string()
|
|
221
|
+
.url()
|
|
222
|
+
.max(4096)
|
|
223
|
+
.refine((value) => {
|
|
224
|
+
try {
|
|
225
|
+
const url = new URL(value);
|
|
226
|
+
return (url.protocol === "https:" &&
|
|
227
|
+
[
|
|
228
|
+
"billing.stripe.com",
|
|
229
|
+
"checkout.stripe.com",
|
|
230
|
+
"invoice.stripe.com",
|
|
231
|
+
"pay.stripe.com",
|
|
232
|
+
].includes(url.hostname) &&
|
|
233
|
+
url.username === "" &&
|
|
234
|
+
url.password === "" &&
|
|
235
|
+
url.port === "");
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}, "must be a supported provider-hosted HTTPS billing URL");
|
|
241
|
+
const billingPaymentReasonSchema = z
|
|
242
|
+
.string()
|
|
243
|
+
.regex(/^[a-z][a-z0-9-]{0,127}$/u, "must be a bounded reason code");
|
|
244
|
+
export const billingAutoTopUpRuleSchema = z
|
|
245
|
+
.object({
|
|
246
|
+
cooldownUntil: timestampSchema.nullable(),
|
|
247
|
+
desired: billingAutoTopUpConfigurationSchema.nullable(),
|
|
248
|
+
effective: billingAutoTopUpConfigurationSchema.nullable(),
|
|
249
|
+
setupUrl: safeBillingUrlSchema.optional(),
|
|
250
|
+
state: z.enum(["disabled", "payment-method-required", "ready"]),
|
|
251
|
+
suspension: z
|
|
252
|
+
.object({
|
|
253
|
+
at: timestampSchema,
|
|
254
|
+
reason: z.enum(["authentication-required", "payment-failed"]),
|
|
255
|
+
})
|
|
256
|
+
.strict()
|
|
257
|
+
.nullable(),
|
|
258
|
+
})
|
|
259
|
+
.strict()
|
|
260
|
+
.superRefine((rule, context) => {
|
|
261
|
+
if (rule.state === "disabled" && rule.effective !== null) {
|
|
262
|
+
context.addIssue({
|
|
263
|
+
code: z.ZodIssueCode.custom,
|
|
264
|
+
message: "a disabled rule cannot remain effective",
|
|
265
|
+
path: ["effective"],
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
if (rule.state === "ready" && rule.effective === null) {
|
|
269
|
+
context.addIssue({
|
|
270
|
+
code: z.ZodIssueCode.custom,
|
|
271
|
+
message: "a ready rule requires effective authority",
|
|
272
|
+
path: ["effective"],
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
if (rule.state !== "payment-method-required" &&
|
|
276
|
+
rule.setupUrl !== undefined) {
|
|
277
|
+
context.addIssue({
|
|
278
|
+
code: z.ZodIssueCode.custom,
|
|
279
|
+
message: "a setup URL is only available while payment authority is required",
|
|
280
|
+
path: ["setupUrl"],
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
export const billingAutoTopUpPreviewSchema = z
|
|
285
|
+
.object({
|
|
286
|
+
action: z.enum(["enable", "edit", "disable", "resume"]),
|
|
287
|
+
after: billingAutoTopUpConfigurationSchema.nullable(),
|
|
288
|
+
before: billingAutoTopUpConfigurationSchema.nullable(),
|
|
289
|
+
currentPeriod: z
|
|
290
|
+
.object({
|
|
291
|
+
end: timestampSchema,
|
|
292
|
+
pending: nonnegativeExactMoneySchema,
|
|
293
|
+
remaining: nonnegativeExactMoneySchema.nullable(),
|
|
294
|
+
settled: nonnegativeExactMoneySchema,
|
|
295
|
+
start: timestampSchema,
|
|
296
|
+
})
|
|
297
|
+
.strict(),
|
|
298
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
299
|
+
expandsAuthority: z.boolean(),
|
|
300
|
+
expiresAt: timestampSchema,
|
|
301
|
+
preview: z.string().min(1).max(128),
|
|
302
|
+
subscribedProjectFees: nonnegativeExactMoneySchema,
|
|
303
|
+
})
|
|
304
|
+
.strict();
|
|
305
|
+
export const billingPaymentOperationSchema = z
|
|
306
|
+
.object({
|
|
307
|
+
createdAt: timestampSchema,
|
|
308
|
+
credit: exactCentMoneySchema,
|
|
309
|
+
gross: nonnegativeExactMoneySchema.nullable(),
|
|
310
|
+
id: z.string().min(1).max(255),
|
|
311
|
+
kind: z.enum(BILLING_PAYMENT_KINDS),
|
|
312
|
+
paymentUrl: safeBillingUrlSchema.optional(),
|
|
313
|
+
reason: billingPaymentReasonSchema.optional(),
|
|
314
|
+
receiptUrl: safeBillingUrlSchema.optional(),
|
|
315
|
+
state: z.enum(BILLING_PAYMENT_STATES),
|
|
316
|
+
tax: nonnegativeExactMoneySchema.nullable(),
|
|
317
|
+
taxStatus: z.enum(["calculated-at-checkout", "confirmed"]),
|
|
318
|
+
updatedAt: timestampSchema,
|
|
319
|
+
})
|
|
320
|
+
.strict()
|
|
321
|
+
.superRefine((operation, context) => {
|
|
322
|
+
if (operation.taxStatus === "calculated-at-checkout") {
|
|
323
|
+
if (operation.tax !== null || operation.gross !== null) {
|
|
324
|
+
context.addIssue({
|
|
325
|
+
code: z.ZodIssueCode.custom,
|
|
326
|
+
message: "tax and gross stay unknown until provider confirmation",
|
|
327
|
+
path: ["taxStatus"],
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (operation.tax === null || operation.gross === null) {
|
|
333
|
+
context.addIssue({
|
|
334
|
+
code: z.ZodIssueCode.custom,
|
|
335
|
+
message: "confirmed tax status requires exact tax and gross amounts",
|
|
336
|
+
path: ["taxStatus"],
|
|
337
|
+
});
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (BigInt(operation.gross.microdollars) !==
|
|
341
|
+
BigInt(operation.credit.microdollars) + BigInt(operation.tax.microdollars)) {
|
|
342
|
+
context.addIssue({
|
|
343
|
+
code: z.ZodIssueCode.custom,
|
|
344
|
+
message: "gross must equal execution credit plus confirmed tax",
|
|
345
|
+
path: ["gross"],
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
export const billingFundingViewSchema = z
|
|
350
|
+
.object({
|
|
351
|
+
automaticExecutionTopUp: z.object({
|
|
352
|
+
ceiling: exactCentMoneySchema.nullable(),
|
|
353
|
+
currentPeriod: z.object({
|
|
354
|
+
end: timestampSchema,
|
|
355
|
+
pending: nonnegativeExactMoneySchema,
|
|
356
|
+
remaining: nonnegativeExactMoneySchema.nullable(),
|
|
357
|
+
settled: nonnegativeExactMoneySchema,
|
|
358
|
+
start: timestampSchema,
|
|
359
|
+
}),
|
|
360
|
+
rule: billingAutoTopUpRuleSchema,
|
|
361
|
+
revision: z.number().int().nonnegative(),
|
|
362
|
+
}),
|
|
363
|
+
credit: z.object({
|
|
364
|
+
amountOwed: nonnegativeExactMoneySchema,
|
|
365
|
+
available: nonnegativeExactMoneySchema,
|
|
366
|
+
reserved: nonnegativeExactMoneySchema,
|
|
367
|
+
}),
|
|
368
|
+
freshness: z.object({ kind: z.literal("authoritative") }),
|
|
369
|
+
paymentOperations: z.array(billingPaymentOperationSchema).max(25),
|
|
370
|
+
subscribedProjectFees: nonnegativeExactMoneySchema,
|
|
371
|
+
})
|
|
372
|
+
.strict()
|
|
373
|
+
.superRefine((view, context) => {
|
|
374
|
+
const ceiling = view.automaticExecutionTopUp.ceiling;
|
|
375
|
+
const period = view.automaticExecutionTopUp.currentPeriod;
|
|
376
|
+
if (ceiling === null) {
|
|
377
|
+
if (period.remaining !== null) {
|
|
378
|
+
context.addIssue({
|
|
379
|
+
code: z.ZodIssueCode.custom,
|
|
380
|
+
message: "remaining must be null when automatic funding is off",
|
|
381
|
+
path: ["automaticExecutionTopUp", "currentPeriod", "remaining"],
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const committed = BigInt(period.pending.microdollars) + BigInt(period.settled.microdollars);
|
|
387
|
+
const cap = BigInt(ceiling.microdollars);
|
|
388
|
+
const expected = cap > committed ? cap - committed : 0n;
|
|
389
|
+
if (period.remaining?.microdollars !== expected.toString()) {
|
|
390
|
+
context.addIssue({
|
|
391
|
+
code: z.ZodIssueCode.custom,
|
|
392
|
+
message: "remaining must reflect settled plus pending gross charges",
|
|
393
|
+
path: ["automaticExecutionTopUp", "currentPeriod", "remaining"],
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
export const BILLING_NOTICE_KINDS = [
|
|
398
|
+
"budget-warning",
|
|
399
|
+
"budget-exhausted",
|
|
400
|
+
"low-credit",
|
|
401
|
+
"automatic-top-up-cap-reached",
|
|
402
|
+
"funding-blocked",
|
|
403
|
+
"payment-pending",
|
|
404
|
+
"payment-succeeded",
|
|
405
|
+
"payment-failed",
|
|
406
|
+
"payment-authentication-required",
|
|
407
|
+
"payment-outcome-unresolved",
|
|
408
|
+
"service-restored",
|
|
409
|
+
];
|
|
410
|
+
export const billingNoticeRecoveryPathSchema = z.enum([
|
|
411
|
+
"#billing",
|
|
412
|
+
"#billing-funding",
|
|
413
|
+
"#billing-notification-settings",
|
|
414
|
+
]);
|
|
415
|
+
export const billingNoticeSchema = z
|
|
416
|
+
.object({
|
|
417
|
+
amounts: z
|
|
418
|
+
.object({
|
|
419
|
+
available: nonnegativeExactMoneySchema.optional(),
|
|
420
|
+
gross: nonnegativeExactMoneySchema.optional(),
|
|
421
|
+
limit: nonnegativeExactMoneySchema.optional(),
|
|
422
|
+
threshold: nonnegativeExactMoneySchema.optional(),
|
|
423
|
+
})
|
|
424
|
+
.strict(),
|
|
425
|
+
detail: z.string().min(1).max(512),
|
|
426
|
+
email: z
|
|
427
|
+
.object({
|
|
428
|
+
attempts: z.number().int().nonnegative().max(100),
|
|
429
|
+
failureCode: billingPaymentReasonSchema.optional(),
|
|
430
|
+
lastAttemptAt: timestampSchema.nullable(),
|
|
431
|
+
state: z.enum(["pending", "delivered", "failed", "suppressed"]),
|
|
432
|
+
})
|
|
433
|
+
.strict(),
|
|
434
|
+
id: z.string().min(1).max(128),
|
|
435
|
+
kind: z.enum(BILLING_NOTICE_KINDS),
|
|
436
|
+
occurredAt: timestampSchema,
|
|
437
|
+
payment: z
|
|
438
|
+
.object({
|
|
439
|
+
operation: z.string().min(1).max(255),
|
|
440
|
+
state: z.enum(BILLING_PAYMENT_STATES),
|
|
441
|
+
})
|
|
442
|
+
.strict()
|
|
443
|
+
.nullable(),
|
|
444
|
+
recoveryPath: billingNoticeRecoveryPathSchema,
|
|
445
|
+
resolvedAt: timestampSchema.nullable(),
|
|
446
|
+
scope: z.discriminatedUnion("kind", [
|
|
447
|
+
z.object({ kind: z.literal("organization") }).strict(),
|
|
448
|
+
z
|
|
449
|
+
.object({ kind: z.literal("project"), project: projectIdSchema })
|
|
450
|
+
.strict(),
|
|
451
|
+
]),
|
|
452
|
+
severity: z.enum(["warning", "critical", "recovery"]),
|
|
453
|
+
state: z.enum(["active", "resolved"]),
|
|
454
|
+
title: z.string().min(1).max(160),
|
|
455
|
+
updatedAt: timestampSchema,
|
|
456
|
+
})
|
|
457
|
+
.strict()
|
|
458
|
+
.superRefine((notice, context) => {
|
|
459
|
+
if ((notice.state === "resolved") !== (notice.resolvedAt !== null)) {
|
|
460
|
+
context.addIssue({
|
|
461
|
+
code: z.ZodIssueCode.custom,
|
|
462
|
+
message: "resolved notices require resolvedAt and active notices forbid it",
|
|
463
|
+
path: ["resolvedAt"],
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
if (notice.email.state === "failed" &&
|
|
467
|
+
notice.email.failureCode === undefined) {
|
|
468
|
+
context.addIssue({
|
|
469
|
+
code: z.ZodIssueCode.custom,
|
|
470
|
+
message: "failed email delivery requires a bounded failure code",
|
|
471
|
+
path: ["email", "failureCode"],
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
export const billingNoticePageSchema = pageSchema(billingNoticeSchema).extend({
|
|
476
|
+
freshness: z.object({ kind: z.literal("authoritative") }),
|
|
477
|
+
});
|
|
478
|
+
export const billingNotificationSettingsSchema = z
|
|
479
|
+
.object({
|
|
480
|
+
criticalEmail: z.literal(true),
|
|
481
|
+
freshness: z.object({ kind: z.literal("authoritative") }),
|
|
482
|
+
lowCreditThreshold: exactCentMoneySchema,
|
|
483
|
+
noncriticalEmail: z.boolean(),
|
|
484
|
+
recipients: z
|
|
485
|
+
.object({
|
|
486
|
+
billingContacts: z.literal("active-billing-role-members"),
|
|
487
|
+
owners: z.literal(true),
|
|
488
|
+
})
|
|
489
|
+
.strict(),
|
|
490
|
+
revision: z.number().int().nonnegative(),
|
|
491
|
+
})
|
|
492
|
+
.strict();
|
|
493
|
+
export const billingNotificationSettingsUpdateRequestSchema = z
|
|
494
|
+
.object({
|
|
495
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
496
|
+
lowCreditThreshold: positiveExactCentMoneySchema.nullable().optional(),
|
|
497
|
+
noncriticalEmail: z.boolean(),
|
|
498
|
+
})
|
|
499
|
+
.strict();
|
|
500
|
+
export const billingRefundRequestCreateSchema = z
|
|
501
|
+
.object({
|
|
502
|
+
amount: positiveExactCentMoneySchema,
|
|
503
|
+
confirmed: z.literal(true),
|
|
504
|
+
paymentOperation: z.string().min(1).max(255),
|
|
505
|
+
reason: z.string().trim().min(1).max(128),
|
|
506
|
+
})
|
|
507
|
+
.strict();
|
|
508
|
+
export const billingRefundResolutionRequestSchema = z
|
|
509
|
+
.object({
|
|
510
|
+
confirmed: z.literal(true),
|
|
511
|
+
decision: z.enum(["completed", "declined"]),
|
|
512
|
+
gross: positiveExactCentMoneySchema.optional(),
|
|
513
|
+
providerRefund: z
|
|
514
|
+
.string()
|
|
515
|
+
.regex(/^re_[A-Za-z0-9_]+$/u, "must be a Stripe refund identifier")
|
|
516
|
+
.max(255)
|
|
517
|
+
.optional(),
|
|
518
|
+
tax: exactCentMoneySchema.optional(),
|
|
519
|
+
})
|
|
520
|
+
.strict()
|
|
521
|
+
.superRefine((request, context) => {
|
|
522
|
+
const completed = request.decision === "completed";
|
|
523
|
+
for (const field of ["gross", "providerRefund", "tax"]) {
|
|
524
|
+
if (completed === (request[field] === undefined)) {
|
|
525
|
+
context.addIssue({
|
|
526
|
+
code: z.ZodIssueCode.custom,
|
|
527
|
+
message: completed
|
|
528
|
+
? `${field} is required for a completed refund`
|
|
529
|
+
: `${field} is not accepted for a declined refund`,
|
|
530
|
+
path: [field],
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
export const billingRefundRequestViewSchema = z
|
|
536
|
+
.object({
|
|
537
|
+
amount: positiveExactCentMoneySchema,
|
|
538
|
+
id: z.string().min(1).max(255),
|
|
539
|
+
paymentOperation: z.string().min(1).max(255),
|
|
540
|
+
requestedAt: timestampSchema,
|
|
541
|
+
state: z.literal("operator-review-pending"),
|
|
542
|
+
})
|
|
543
|
+
.strict();
|
|
544
|
+
export const billingBudgetUpdateRequestSchema = z.object({
|
|
545
|
+
advisoryBudget: exactCentMoneySchema.nullable(),
|
|
546
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
547
|
+
hardCap: exactCentMoneySchema.nullable(),
|
|
548
|
+
});
|
|
549
|
+
const billingBudgetSettingsSchema = z.object({
|
|
550
|
+
advisoryBudget: nonnegativeExactMoneySchema.nullable(),
|
|
551
|
+
hardCap: nonnegativeExactMoneySchema.nullable(),
|
|
552
|
+
});
|
|
553
|
+
export const billingBudgetPolicySchema = z
|
|
554
|
+
.object({
|
|
555
|
+
desired: billingBudgetSettingsSchema,
|
|
556
|
+
desiredRevision: z.number().int().nonnegative(),
|
|
557
|
+
effectiveRevision: z.number().int().nonnegative(),
|
|
558
|
+
pending: z.boolean(),
|
|
559
|
+
})
|
|
560
|
+
.superRefine((policy, context) => {
|
|
561
|
+
if (!policy.pending &&
|
|
562
|
+
policy.desiredRevision !== policy.effectiveRevision) {
|
|
563
|
+
context.addIssue({
|
|
564
|
+
code: z.ZodIssueCode.custom,
|
|
565
|
+
message: "different desired and effective budget revisions must remain pending",
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
export const billingPeriodSummarySchema = z.object({
|
|
570
|
+
advisoryBudget: nonnegativeExactMoneySchema.optional(),
|
|
571
|
+
hardCap: nonnegativeExactMoneySchema.optional(),
|
|
572
|
+
remainingToHardCap: nonnegativeExactMoneySchema.optional(),
|
|
573
|
+
advisoryBudgetProgress: z
|
|
574
|
+
.object({
|
|
575
|
+
committed: nonnegativeExactMoneySchema,
|
|
576
|
+
remaining: nonnegativeExactMoneySchema,
|
|
577
|
+
})
|
|
578
|
+
.optional(),
|
|
579
|
+
automaticExecutionTopUp: z.object({
|
|
580
|
+
cap: nonnegativeExactMoneySchema.optional(),
|
|
581
|
+
pending: nonnegativeExactMoneySchema,
|
|
582
|
+
remainingToCap: nonnegativeExactMoneySchema.optional(),
|
|
583
|
+
settled: nonnegativeExactMoneySchema,
|
|
584
|
+
}),
|
|
585
|
+
subscribedProjectFees: nonnegativeExactMoneySchema,
|
|
586
|
+
reservedUsage: nonnegativeExactMoneySchema,
|
|
587
|
+
settledUsage: nonnegativeExactMoneySchema,
|
|
588
|
+
start: timestampSchema,
|
|
589
|
+
end: timestampSchema,
|
|
590
|
+
});
|
|
591
|
+
export const billingSummarySchema = z
|
|
592
|
+
.object({
|
|
593
|
+
activation: z.object({
|
|
594
|
+
boundary: timestampSchema,
|
|
595
|
+
mode: z.enum(BILLING_ACTIVATION_MODES),
|
|
596
|
+
}),
|
|
597
|
+
blockingReasons: z.array(z.enum(BILLING_BLOCK_REASONS)),
|
|
598
|
+
budgetPolicy: billingBudgetPolicySchema,
|
|
599
|
+
closedAt: timestampSchema.optional(),
|
|
600
|
+
credit: z.object({
|
|
601
|
+
available: signedExactMoneySchema,
|
|
602
|
+
consumed: nonnegativeExactMoneySchema,
|
|
603
|
+
reserved: nonnegativeExactMoneySchema,
|
|
604
|
+
}),
|
|
605
|
+
desiredRevision: z.number().int().positive(),
|
|
606
|
+
effectiveRevision: z.number().int().positive(),
|
|
607
|
+
freshness: z.object({ kind: z.literal("authoritative") }),
|
|
608
|
+
includedProject: projectIdSchema.optional(),
|
|
609
|
+
period: billingPeriodSummarySchema.optional(),
|
|
610
|
+
pending: z.boolean(),
|
|
611
|
+
priceVersion: z.string().min(1).max(64),
|
|
612
|
+
trialExpiresAt: timestampSchema.optional(),
|
|
613
|
+
})
|
|
614
|
+
.superRefine((summary, context) => {
|
|
615
|
+
if (!summary.pending &&
|
|
616
|
+
summary.desiredRevision !== summary.effectiveRevision) {
|
|
617
|
+
context.addIssue({
|
|
618
|
+
code: z.ZodIssueCode.custom,
|
|
619
|
+
message: "different desired and effective revisions must remain pending",
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
export const billingBudgetUpdateResponseSchema = z.object({
|
|
624
|
+
budgetPolicy: billingBudgetPolicySchema,
|
|
625
|
+
freshness: z.object({ kind: z.literal("authoritative") }),
|
|
626
|
+
});
|
|
627
|
+
export const billingBudgetUpdateRequestHeadersSchema = requiredIdempotencyRequestHeaderSchema;
|
|
628
|
+
export const billingLedgerEntrySchema = z.object({
|
|
629
|
+
amount: z.object({
|
|
630
|
+
currency: z.literal(BILLING_CURRENCY),
|
|
631
|
+
microdollars: microdollarAmountSchema,
|
|
632
|
+
scale: z.literal(BILLING_AMOUNT_SCALE),
|
|
633
|
+
}),
|
|
634
|
+
kind: z.enum(BILLING_ENTRY_KINDS),
|
|
635
|
+
note: z
|
|
636
|
+
.enum(BILLING_LEDGER_ENTRY_NOTES)
|
|
637
|
+
.meta({
|
|
638
|
+
description: "Present when an entry moved no money despite its kind. provider-details-attached: the provider reported details of a payment already recorded; the amount is zero.",
|
|
639
|
+
})
|
|
640
|
+
.optional(),
|
|
641
|
+
period: timestampSchema.optional(),
|
|
642
|
+
recordedAt: timestampSchema,
|
|
643
|
+
reference: z.object({
|
|
644
|
+
attempt: attemptIdSchema.optional(),
|
|
645
|
+
creditLot: z.string().min(1).max(128).optional(),
|
|
646
|
+
event: z.string().min(1).max(255),
|
|
647
|
+
paymentOperation: z.string().min(1).max(255).optional(),
|
|
648
|
+
}),
|
|
649
|
+
sequence: nonnegativeMicrodollarAmountSchema.refine((value) => value !== "0", "must be positive"),
|
|
650
|
+
});
|
|
651
|
+
export const billingLedgerRequestSchema = pageRequestSchema;
|
|
652
|
+
export const billingLedgerPageSchema = pageSchema(billingLedgerEntrySchema).extend({
|
|
653
|
+
freshness: z.object({ kind: z.literal("authoritative") }),
|
|
654
|
+
});
|
|
655
|
+
export const PROJECT_BILLING_ACTIONS = [
|
|
656
|
+
"add",
|
|
657
|
+
"cancel",
|
|
658
|
+
"transfer-included",
|
|
659
|
+
];
|
|
660
|
+
export const projectBillingQuoteRequestSchema = z
|
|
661
|
+
.object({
|
|
662
|
+
action: z.enum(PROJECT_BILLING_ACTIONS),
|
|
663
|
+
project: projectIdSchema,
|
|
664
|
+
fromProject: projectIdSchema.optional(),
|
|
665
|
+
})
|
|
666
|
+
.strict();
|
|
667
|
+
export const projectBillingQuoteSchema = projectBillingQuoteRequestSchema.extend({
|
|
668
|
+
quote: z.string().min(1).max(128),
|
|
669
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
670
|
+
expiresAt: timestampSchema,
|
|
671
|
+
charge: nonnegativeExactMoneySchema,
|
|
672
|
+
monthlyProjectFees: nonnegativeExactMoneySchema,
|
|
673
|
+
effectiveAt: timestampSchema,
|
|
674
|
+
formerIncludedWillBlock: z.boolean(),
|
|
675
|
+
});
|
|
676
|
+
export const projectBillingChangeRequestSchema = z
|
|
677
|
+
.object({
|
|
678
|
+
quote: z.string().min(1).max(128),
|
|
679
|
+
expectedRevision: z.number().int().nonnegative(),
|
|
680
|
+
confirmed: z.literal(true),
|
|
681
|
+
})
|
|
682
|
+
.strict();
|
|
683
|
+
export const projectBillingStateSchema = z.object({
|
|
684
|
+
includedProject: projectIdSchema.optional(),
|
|
685
|
+
desiredRevision: z.number().int().positive(),
|
|
686
|
+
effectiveRevision: z.number().int().nonnegative(),
|
|
687
|
+
pending: z.boolean(),
|
|
688
|
+
recurringProjectFees: nonnegativeExactMoneySchema,
|
|
689
|
+
projects: z.array(z.object({
|
|
690
|
+
name: z.string(),
|
|
691
|
+
project: projectIdSchema,
|
|
692
|
+
access: z.enum(["included", "paid", "blocked"]),
|
|
693
|
+
paidThroughAt: timestampSchema.optional(),
|
|
694
|
+
renewalGraceUntil: timestampSchema.optional(),
|
|
695
|
+
cancellationAt: timestampSchema.optional(),
|
|
696
|
+
deleted: z.boolean(),
|
|
697
|
+
})),
|
|
698
|
+
pendingOperations: z.array(z.object({
|
|
699
|
+
id: z.string().min(1).max(255),
|
|
700
|
+
kind: z.enum(["add", "cancel"]),
|
|
701
|
+
project: projectIdSchema,
|
|
702
|
+
state: z.enum(["pending", "action-required"]),
|
|
703
|
+
paymentUrl: z.string().url().optional(),
|
|
704
|
+
reason: z.string().min(1).max(128).optional(),
|
|
705
|
+
})),
|
|
706
|
+
});
|
|
707
|
+
export const billingPortalSchema = z.object({ url: z.string().url() });
|
|
708
|
+
const savedCardSchema = z
|
|
709
|
+
.object({
|
|
710
|
+
brand: z.string().min(1).max(32),
|
|
711
|
+
last4: z.string().regex(/^\d{4}$/u),
|
|
712
|
+
expMonth: z.number().int().min(1).max(12),
|
|
713
|
+
expYear: z.number().int().min(2000).max(2200),
|
|
714
|
+
})
|
|
715
|
+
.strict();
|
|
716
|
+
/** How a saved payment method is named to a person, on every surface alike. */
|
|
717
|
+
const paymentMethodLabelSchema = z.string().min(1).max(200);
|
|
718
|
+
/**
|
|
719
|
+
* The organization's saved payment method (W9-09, widened by W9-14): the one
|
|
720
|
+
* method automatic top-ups and project subscriptions charge. It is the Stripe
|
|
721
|
+
* customer's default payment method, read by authenticated provider call and
|
|
722
|
+
* never stored by GreatWait beyond the provider's own identifier.
|
|
723
|
+
*
|
|
724
|
+
* `method` says what it is. A card keeps its brand and last four digits; Link
|
|
725
|
+
* carries the email it is registered to when the provider reports one; any
|
|
726
|
+
* other type the provider's checkout offered (Cash App Pay, Amazon Pay,
|
|
727
|
+
* Klarna) carries the provider's type name. Every variant carries `label`,
|
|
728
|
+
* the sentence-ready name the dashboard, command line and MCP all show, so no
|
|
729
|
+
* client needs its own table of provider types. `method` is null when nothing
|
|
730
|
+
* is saved.
|
|
731
|
+
*
|
|
732
|
+
* `card` is the pre-W9-14 field, kept so a client written against it keeps
|
|
733
|
+
* working: it is set exactly when `method.type` is `card`, and null otherwise
|
|
734
|
+
* — including when a non-card method is saved, which such a client reads as
|
|
735
|
+
* "no card".
|
|
736
|
+
*/
|
|
737
|
+
export const billingPaymentMethodSchema = z
|
|
738
|
+
.object({
|
|
739
|
+
card: savedCardSchema.nullable(),
|
|
740
|
+
method: z
|
|
741
|
+
.discriminatedUnion("type", [
|
|
742
|
+
savedCardSchema
|
|
743
|
+
.extend({
|
|
744
|
+
type: z.literal("card"),
|
|
745
|
+
label: paymentMethodLabelSchema,
|
|
746
|
+
})
|
|
747
|
+
.strict(),
|
|
748
|
+
z
|
|
749
|
+
.object({
|
|
750
|
+
type: z.literal("link"),
|
|
751
|
+
label: paymentMethodLabelSchema,
|
|
752
|
+
email: z.string().min(3).max(320).nullable(),
|
|
753
|
+
})
|
|
754
|
+
.strict(),
|
|
755
|
+
z
|
|
756
|
+
.object({
|
|
757
|
+
type: z.literal("other"),
|
|
758
|
+
label: paymentMethodLabelSchema,
|
|
759
|
+
providerType: z.string().regex(/^[a-z][a-z0-9_]{0,63}$/u),
|
|
760
|
+
})
|
|
761
|
+
.strict(),
|
|
762
|
+
])
|
|
763
|
+
.nullable(),
|
|
764
|
+
})
|
|
765
|
+
.strict();
|
|
766
|
+
/**
|
|
767
|
+
* Where hosted card setup returns. Optional: the configured dashboard billing
|
|
768
|
+
* page is the default, and a supplied address must share its origin, so the
|
|
769
|
+
* operation cannot be used to send a customer to a page GreatWait does not own.
|
|
770
|
+
*/
|
|
771
|
+
export const billingPaymentMethodSetupRequestSchema = z
|
|
772
|
+
.object({
|
|
773
|
+
returnUrl: z.string().url().max(2048).optional(),
|
|
774
|
+
})
|
|
775
|
+
.strict();
|
|
776
|
+
/** The hosted card-setup Checkout session a browser returned from. */
|
|
777
|
+
export const billingPaymentMethodConfirmRequestSchema = z
|
|
778
|
+
.object({
|
|
779
|
+
checkoutSession: z
|
|
780
|
+
.string()
|
|
781
|
+
.min(4)
|
|
782
|
+
.max(255)
|
|
783
|
+
.regex(/^cs_[A-Za-z0-9_]+$/u),
|
|
784
|
+
})
|
|
785
|
+
.strict();
|
|
786
|
+
/**
|
|
787
|
+
* Removing the card on file (W9-09). The literal `true` is the caller's
|
|
788
|
+
* acknowledgement of what removal does: project subscriptions stop renewing,
|
|
789
|
+
* paid projects run to the end of the period already paid for and then stop,
|
|
790
|
+
* and automatic top-up turns off.
|
|
791
|
+
*/
|
|
792
|
+
export const billingPaymentMethodRemoveRequestSchema = z
|
|
793
|
+
.object({ confirmed: z.literal(true) })
|
|
794
|
+
.strict();
|
|
795
|
+
/**
|
|
796
|
+
* One project subscription charge (W9-09): a provider invoice for the
|
|
797
|
+
* organization's project subscription, listed beside execution-credit
|
|
798
|
+
* payments so a customer who was charged for a project sees the charge and its
|
|
799
|
+
* receipt. `amount` is the invoice total, tax included. `receiptUrl` is the
|
|
800
|
+
* provider-hosted invoice page when there is one.
|
|
801
|
+
*/
|
|
802
|
+
export const billingInvoiceSchema = z
|
|
803
|
+
.object({
|
|
804
|
+
id: z.string().min(1).max(255),
|
|
805
|
+
createdAt: timestampSchema,
|
|
806
|
+
amount: nonnegativeExactMoneySchema,
|
|
807
|
+
state: z.enum(["paid", "open", "void", "uncollectible"]),
|
|
808
|
+
receiptUrl: z.string().url().optional(),
|
|
809
|
+
})
|
|
810
|
+
.strict();
|
|
811
|
+
/** Execution-credit payment history, with a bounded continuation. */
|
|
812
|
+
export const billingPaymentHistoryPageSchema = pageSchema(billingPaymentOperationSchema).strict();
|
|
813
|
+
/** Project subscription history; an empty filtered page may still have a cursor. */
|
|
814
|
+
export const billingInvoiceHistoryPageSchema = pageSchema(billingInvoiceSchema).strict();
|
|
815
|
+
/** Project subscription charges, most recent first, at most 24. */
|
|
816
|
+
export const billingInvoiceListSchema = z
|
|
817
|
+
.object({ data: z.array(billingInvoiceSchema) })
|
|
818
|
+
.strict();
|
|
819
|
+
/**
|
|
820
|
+
* The stable title of the refusal a card-dependent change receives when the
|
|
821
|
+
* organization has no card on file (W9-09): enabling or resuming automatic
|
|
822
|
+
* top-up, and quoting or confirming a paid project addition.
|
|
823
|
+
*
|
|
824
|
+
* **Why a title and not a new problem code.** The published CLI and SDK parse
|
|
825
|
+
* error bodies with this package's `problemSchema`, whose `code` is a closed
|
|
826
|
+
* enum, so a code an installed client does not know turns a precise refusal into
|
|
827
|
+
* "failed with status 409" with no problem at all. The refusal is therefore
|
|
828
|
+
* `state_conflict` — which is what it is: the request is well formed and would
|
|
829
|
+
* succeed once a card is saved — and this exact title is the discriminator.
|
|
830
|
+
* Detect it as `code === "state_conflict" && title ===
|
|
831
|
+
* BILLING_PAYMENT_METHOD_REQUIRED_TITLE`.
|
|
832
|
+
*/
|
|
833
|
+
export const BILLING_PAYMENT_METHOD_REQUIRED_TITLE = "A card on file is required";
|