@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/forecast.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
1
|
+
import { z } from "./zod.js";
|
|
2
2
|
import type { FieldError } from "./problems.js";
|
|
3
3
|
import { type Freshness } from "./protocol.js";
|
|
4
4
|
import type { ForecastPartitionBucket } from "./partition.js";
|
|
@@ -53,10 +53,11 @@ export declare const FORECAST_BOUNDS: {
|
|
|
53
53
|
* argument for refusing rather than under-reporting collapses if staleness is
|
|
54
54
|
* the one degradation that gets through as a number.
|
|
55
55
|
*/
|
|
56
|
-
readonly maxLagSeconds:
|
|
56
|
+
readonly maxLagSeconds: number;
|
|
57
57
|
/**
|
|
58
|
-
*
|
|
59
|
-
* the answer as short.
|
|
58
|
+
* Actual recurrence work units (shared cron advances or interval-series
|
|
59
|
+
* calculations) before a partition reports the answer as short. Output-cell
|
|
60
|
+
* allocation is bounded independently by maxGroupsPerPartition.
|
|
60
61
|
*
|
|
61
62
|
* Published rather than kept internal so a refusal is classifiable: a shadow
|
|
62
63
|
* comparison that sees a refusal needs to be able to tell "we are near a
|
|
@@ -83,7 +84,7 @@ export declare const FORECAST_BOUNDS: {
|
|
|
83
84
|
* an incident. `freshness.lagSeconds` reports the actual age on every answer;
|
|
84
85
|
* this is the bound it lives inside.
|
|
85
86
|
*/
|
|
86
|
-
readonly refreshCeilingSeconds:
|
|
87
|
+
readonly refreshCeilingSeconds: number;
|
|
87
88
|
/**
|
|
88
89
|
* Shortest gap between refreshes once something *has* been written.
|
|
89
90
|
*
|
|
@@ -92,7 +93,7 @@ export declare const FORECAST_BOUNDS: {
|
|
|
92
93
|
* projection that rebuilt on every poll would be the cost this whole design
|
|
93
94
|
* exists to avoid.
|
|
94
95
|
*/
|
|
95
|
-
readonly refreshFloorSeconds:
|
|
96
|
+
readonly refreshFloorSeconds: number;
|
|
96
97
|
/**
|
|
97
98
|
* How far below `now` a window may begin.
|
|
98
99
|
*
|
|
@@ -102,7 +103,7 @@ export declare const FORECAST_BOUNDS: {
|
|
|
102
103
|
* because the caller's `now` is a second behind. Further back than that is a
|
|
103
104
|
* question about the past, which a forecast does not answer.
|
|
104
105
|
*/
|
|
105
|
-
readonly slackSeconds:
|
|
106
|
+
readonly slackSeconds: number;
|
|
106
107
|
/**
|
|
107
108
|
* Customer keys named individually in one bucket before the rest are summed.
|
|
108
109
|
*
|
|
@@ -120,20 +121,20 @@ export declare const FORECAST_BOUNDS: {
|
|
|
120
121
|
* the total and the latency split, which every answer carries.
|
|
121
122
|
*/
|
|
122
123
|
export declare const FORECAST_BREAKDOWNS: readonly ["none", "partitionKey"];
|
|
123
|
-
export declare const forecastBreakdownSchema:
|
|
124
|
+
export declare const forecastBreakdownSchema: import("zod").ZodEnum<{
|
|
124
125
|
none: "none";
|
|
125
126
|
partitionKey: "partitionKey";
|
|
126
127
|
}>;
|
|
127
128
|
export type ForecastBreakdown = z.infer<typeof forecastBreakdownSchema>;
|
|
128
|
-
export declare const forecastRequestSchema:
|
|
129
|
-
breakdown:
|
|
129
|
+
export declare const forecastRequestSchema: import("zod").ZodObject<{
|
|
130
|
+
breakdown: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
130
131
|
none: "none";
|
|
131
132
|
partitionKey: "partitionKey";
|
|
132
133
|
}>>;
|
|
133
|
-
bucketSeconds:
|
|
134
|
-
from:
|
|
135
|
-
to:
|
|
136
|
-
},
|
|
134
|
+
bucketSeconds: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
135
|
+
from: import("zod").ZodOptional<import("zod").ZodString>;
|
|
136
|
+
to: import("zod").ZodOptional<import("zod").ZodString>;
|
|
137
|
+
}, import("zod/v4/core").$strip>;
|
|
137
138
|
export type ForecastRequest = z.infer<typeof forecastRequestSchema>;
|
|
138
139
|
export type ForecastRequestParse = {
|
|
139
140
|
readonly errors: readonly FieldError[];
|
|
@@ -197,46 +198,145 @@ export declare function forecastBucketStartMs(instantMs: number, bucketSeconds:
|
|
|
197
198
|
* third latency class fails a test here rather than silently vanishing from
|
|
198
199
|
* every forecast.
|
|
199
200
|
*/
|
|
200
|
-
export declare const forecastLatencyCountsSchema:
|
|
201
|
-
bulk:
|
|
202
|
-
realtime:
|
|
203
|
-
},
|
|
201
|
+
export declare const forecastLatencyCountsSchema: import("zod").ZodObject<{
|
|
202
|
+
bulk: import("zod").ZodNumber;
|
|
203
|
+
realtime: import("zod").ZodNumber;
|
|
204
|
+
}, import("zod/v4/core").$strip>;
|
|
204
205
|
export type ForecastLatencyCounts = z.infer<typeof forecastLatencyCountsSchema>;
|
|
205
|
-
export declare const forecastBucketSchema:
|
|
206
|
-
byLatencyClass:
|
|
207
|
-
bulk:
|
|
208
|
-
realtime:
|
|
209
|
-
},
|
|
210
|
-
byPartitionKey:
|
|
211
|
-
count:
|
|
212
|
-
nextFireCount:
|
|
213
|
-
otherPartitionKeyCount:
|
|
214
|
-
start:
|
|
215
|
-
},
|
|
206
|
+
export declare const forecastBucketSchema: import("zod").ZodObject<{
|
|
207
|
+
byLatencyClass: import("zod").ZodObject<{
|
|
208
|
+
bulk: import("zod").ZodNumber;
|
|
209
|
+
realtime: import("zod").ZodNumber;
|
|
210
|
+
}, import("zod/v4/core").$strip>;
|
|
211
|
+
byPartitionKey: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodNumber>>;
|
|
212
|
+
count: import("zod").ZodNumber;
|
|
213
|
+
nextFireCount: import("zod").ZodNumber;
|
|
214
|
+
otherPartitionKeyCount: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
215
|
+
start: import("zod").ZodString;
|
|
216
|
+
}, import("zod/v4/core").$strip>;
|
|
216
217
|
export type ForecastBucket = z.infer<typeof forecastBucketSchema>;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
218
|
+
/** Capability opt-in prevents old clients that read only counts from mistaking
|
|
219
|
+
* a lower bound for complete work. Older servers safely ignore this header. */
|
|
220
|
+
export declare const FORECAST_PARTIAL_ACCEPT_HEADER = "X-Greatwait-Accept-Partial-Forecast";
|
|
221
|
+
export declare const forecastRequestHeadersSchema: import("zod").ZodObject<{
|
|
222
|
+
"X-Greatwait-Accept-Partial-Forecast": import("zod").ZodOptional<import("zod").ZodLiteral<"true">>;
|
|
223
|
+
}, import("zod/v4/core").$strip>;
|
|
224
|
+
export declare const forecastCoverageSchema: import("zod").ZodObject<{
|
|
225
|
+
complete: import("zod").ZodBoolean;
|
|
226
|
+
countMeaning: import("zod").ZodEnum<{
|
|
227
|
+
"complete-total": "complete-total";
|
|
228
|
+
"lower-bound": "lower-bound";
|
|
229
|
+
}>;
|
|
230
|
+
projectedWindow: import("zod").ZodObject<{
|
|
231
|
+
from: import("zod").ZodString;
|
|
232
|
+
to: import("zod").ZodString;
|
|
233
|
+
}, import("zod/v4/core").$strip>;
|
|
234
|
+
completeThrough: import("zod").ZodString;
|
|
235
|
+
heads: import("zod").ZodObject<{
|
|
236
|
+
groupsRead: import("zod").ZodNumber;
|
|
237
|
+
occurrencesCounted: import("zod").ZodNumber;
|
|
238
|
+
complete: import("zod").ZodBoolean;
|
|
239
|
+
selection: import("zod").ZodLiteral<"earliest bucket, latency class, partition key groups">;
|
|
240
|
+
lastGroup: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
241
|
+
start: import("zod").ZodString;
|
|
242
|
+
latencyClass: import("zod").ZodEnum<{
|
|
243
|
+
realtime: "realtime";
|
|
244
|
+
bulk: "bulk";
|
|
245
|
+
}>;
|
|
246
|
+
partitionKey: import("zod").ZodString;
|
|
247
|
+
}, import("zod/v4/core").$strip>>;
|
|
248
|
+
}, import("zod/v4/core").$strip>;
|
|
249
|
+
recurring: import("zod").ZodObject<{
|
|
250
|
+
schedulesRead: import("zod").ZodNumber;
|
|
251
|
+
populationComplete: import("zod").ZodBoolean;
|
|
252
|
+
selection: import("zod").ZodLiteral<"oldest eligible active recurring schedules by createdAt and scheduleId">;
|
|
253
|
+
firstScheduleId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
254
|
+
lastScheduleId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
255
|
+
}, import("zod/v4/core").$strip>;
|
|
256
|
+
work: import("zod").ZodObject<{
|
|
257
|
+
usedUnits: import("zod").ZodNumber;
|
|
258
|
+
limitUnits: import("zod").ZodNumber;
|
|
259
|
+
}, import("zod/v4/core").$strip>;
|
|
260
|
+
boundsReached: import("zod").ZodArray<import("zod").ZodObject<{
|
|
261
|
+
kind: import("zod").ZodEnum<{
|
|
262
|
+
"head-cells": "head-cells";
|
|
263
|
+
"recurring-series": "recurring-series";
|
|
264
|
+
"projection-work": "projection-work";
|
|
265
|
+
"projection-cells": "projection-cells";
|
|
266
|
+
}>;
|
|
267
|
+
limit: import("zod").ZodNumber;
|
|
268
|
+
}, import("zod/v4/core").$strip>>;
|
|
269
|
+
}, import("zod/v4/core").$strip>;
|
|
270
|
+
export type ForecastCoverage = z.infer<typeof forecastCoverageSchema>;
|
|
271
|
+
export declare const forecastSchema: import("zod").ZodObject<{
|
|
272
|
+
coverage: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
273
|
+
complete: import("zod").ZodBoolean;
|
|
274
|
+
countMeaning: import("zod").ZodEnum<{
|
|
275
|
+
"complete-total": "complete-total";
|
|
276
|
+
"lower-bound": "lower-bound";
|
|
277
|
+
}>;
|
|
278
|
+
projectedWindow: import("zod").ZodObject<{
|
|
279
|
+
from: import("zod").ZodString;
|
|
280
|
+
to: import("zod").ZodString;
|
|
281
|
+
}, import("zod/v4/core").$strip>;
|
|
282
|
+
completeThrough: import("zod").ZodString;
|
|
283
|
+
heads: import("zod").ZodObject<{
|
|
284
|
+
groupsRead: import("zod").ZodNumber;
|
|
285
|
+
occurrencesCounted: import("zod").ZodNumber;
|
|
286
|
+
complete: import("zod").ZodBoolean;
|
|
287
|
+
selection: import("zod").ZodLiteral<"earliest bucket, latency class, partition key groups">;
|
|
288
|
+
lastGroup: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
289
|
+
start: import("zod").ZodString;
|
|
290
|
+
latencyClass: import("zod").ZodEnum<{
|
|
291
|
+
realtime: "realtime";
|
|
292
|
+
bulk: "bulk";
|
|
293
|
+
}>;
|
|
294
|
+
partitionKey: import("zod").ZodString;
|
|
295
|
+
}, import("zod/v4/core").$strip>>;
|
|
296
|
+
}, import("zod/v4/core").$strip>;
|
|
297
|
+
recurring: import("zod").ZodObject<{
|
|
298
|
+
schedulesRead: import("zod").ZodNumber;
|
|
299
|
+
populationComplete: import("zod").ZodBoolean;
|
|
300
|
+
selection: import("zod").ZodLiteral<"oldest eligible active recurring schedules by createdAt and scheduleId">;
|
|
301
|
+
firstScheduleId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
302
|
+
lastScheduleId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
303
|
+
}, import("zod/v4/core").$strip>;
|
|
304
|
+
work: import("zod").ZodObject<{
|
|
305
|
+
usedUnits: import("zod").ZodNumber;
|
|
306
|
+
limitUnits: import("zod").ZodNumber;
|
|
307
|
+
}, import("zod/v4/core").$strip>;
|
|
308
|
+
boundsReached: import("zod").ZodArray<import("zod").ZodObject<{
|
|
309
|
+
kind: import("zod").ZodEnum<{
|
|
310
|
+
"head-cells": "head-cells";
|
|
311
|
+
"recurring-series": "recurring-series";
|
|
312
|
+
"projection-work": "projection-work";
|
|
313
|
+
"projection-cells": "projection-cells";
|
|
314
|
+
}>;
|
|
315
|
+
limit: import("zod").ZodNumber;
|
|
316
|
+
}, import("zod/v4/core").$strip>>;
|
|
317
|
+
}, import("zod/v4/core").$strip>>;
|
|
318
|
+
buckets: import("zod").ZodArray<import("zod").ZodObject<{
|
|
319
|
+
byLatencyClass: import("zod").ZodObject<{
|
|
320
|
+
bulk: import("zod").ZodNumber;
|
|
321
|
+
realtime: import("zod").ZodNumber;
|
|
322
|
+
}, import("zod/v4/core").$strip>;
|
|
323
|
+
byPartitionKey: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodNumber>>;
|
|
324
|
+
count: import("zod").ZodNumber;
|
|
325
|
+
nextFireCount: import("zod").ZodNumber;
|
|
326
|
+
otherPartitionKeyCount: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
327
|
+
start: import("zod").ZodString;
|
|
328
|
+
}, import("zod/v4/core").$strip>>;
|
|
329
|
+
freshness: import("zod").ZodObject<{
|
|
330
|
+
asOf: import("zod").ZodString;
|
|
331
|
+
kind: import("zod").ZodLiteral<"projected">;
|
|
332
|
+
lagSeconds: import("zod").ZodNumber;
|
|
333
|
+
}, import("zod/v4/core").$strip>;
|
|
334
|
+
window: import("zod").ZodObject<{
|
|
335
|
+
bucketSeconds: import("zod").ZodNumber;
|
|
336
|
+
from: import("zod").ZodString;
|
|
337
|
+
to: import("zod").ZodString;
|
|
338
|
+
}, import("zod/v4/core").$strip>;
|
|
339
|
+
}, import("zod/v4/core").$strip>;
|
|
240
340
|
export type Forecast = z.infer<typeof forecastSchema>;
|
|
241
341
|
/** One bucket, summed across every shard, before it is rendered. */
|
|
242
342
|
export interface ForecastMergedBucket {
|
|
@@ -245,6 +345,7 @@ export interface ForecastMergedBucket {
|
|
|
245
345
|
readonly byPartitionKey: Record<string, number>;
|
|
246
346
|
count: number;
|
|
247
347
|
nextFireCount: number;
|
|
348
|
+
omittedPartitionKeyCount?: number;
|
|
248
349
|
unkeyedCount: number;
|
|
249
350
|
}
|
|
250
351
|
/**
|
|
@@ -301,26 +402,15 @@ export type ForecastAnswerDecision = {
|
|
|
301
402
|
/**
|
|
302
403
|
* Whether a gathered forecast may be published, and how old it is.
|
|
303
404
|
*
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
* bucket total and nothing else — not a degraded flag, not `freshness` — so a
|
|
308
|
-
* degraded answer reads to it as a quiet book, and a quiet book makes it
|
|
309
|
-
* release capacity. Its own failure path is fail-safe: a request that errors
|
|
310
|
-
* makes it hold its last good reading. So the honest degradation is the one
|
|
311
|
-
* that errors.
|
|
312
|
-
*
|
|
313
|
-
* The three are distinct because they mean different things to whoever is
|
|
314
|
-
* looking: a partition that did not answer is an availability problem, a book
|
|
315
|
-
* past the projection bound is a capacity problem with a published number
|
|
316
|
-
* beside it, and an answer older than the bound is a partition that has stopped
|
|
317
|
-
* refreshing.
|
|
405
|
+
* Unavailable and stale sources always refuse. Work-bound partial answers are
|
|
406
|
+
* permitted only for a reader that explicitly understands coverage; the
|
|
407
|
+
* default retains the count-only legacy consumer's safe failure behavior.
|
|
318
408
|
*
|
|
319
409
|
* `asOfMs` is the **oldest** across the shards, for the reason
|
|
320
410
|
* `projectionCoverage` takes the oldest checkpoint: one busy shard must not be
|
|
321
411
|
* allowed to vouch for three quiet ones.
|
|
322
412
|
*/
|
|
323
|
-
export declare function decideForecastAnswer(answers: readonly ForecastShardAnswer[], nowMs: number): ForecastAnswerDecision;
|
|
413
|
+
export declare function decideForecastAnswer(answers: readonly ForecastShardAnswer[], nowMs: number, acceptPartial?: boolean): ForecastAnswerDecision;
|
|
324
414
|
/**
|
|
325
415
|
* The version of the transitional window shape.
|
|
326
416
|
*
|
|
@@ -329,32 +419,32 @@ export declare function decideForecastAnswer(answers: readonly ForecastShardAnsw
|
|
|
329
419
|
* rather than one it discovers.
|
|
330
420
|
*/
|
|
331
421
|
export declare const FORECAST_WINDOW_VERSION = "2026-08-09";
|
|
332
|
-
export declare const forecastWindowBucketSchema:
|
|
333
|
-
byTenant:
|
|
334
|
-
count:
|
|
335
|
-
nextFireCount:
|
|
336
|
-
otherCount:
|
|
337
|
-
start:
|
|
338
|
-
},
|
|
422
|
+
export declare const forecastWindowBucketSchema: import("zod").ZodObject<{
|
|
423
|
+
byTenant: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodNumber>;
|
|
424
|
+
count: import("zod").ZodNumber;
|
|
425
|
+
nextFireCount: import("zod").ZodNumber;
|
|
426
|
+
otherCount: import("zod").ZodNumber;
|
|
427
|
+
start: import("zod").ZodString;
|
|
428
|
+
}, import("zod/v4/core").$strip>;
|
|
339
429
|
export type ForecastWindowBucket = z.infer<typeof forecastWindowBucketSchema>;
|
|
340
|
-
export declare const forecastWindowsSchema:
|
|
341
|
-
bucketSeconds:
|
|
342
|
-
buckets:
|
|
343
|
-
byTenant:
|
|
344
|
-
count:
|
|
345
|
-
nextFireCount:
|
|
346
|
-
otherCount:
|
|
347
|
-
start:
|
|
348
|
-
},
|
|
349
|
-
freshness:
|
|
350
|
-
kind:
|
|
351
|
-
},
|
|
352
|
-
asOf:
|
|
353
|
-
kind:
|
|
354
|
-
lagSeconds:
|
|
355
|
-
},
|
|
356
|
-
version:
|
|
357
|
-
},
|
|
430
|
+
export declare const forecastWindowsSchema: import("zod").ZodObject<{
|
|
431
|
+
bucketSeconds: import("zod").ZodNumber;
|
|
432
|
+
buckets: import("zod").ZodArray<import("zod").ZodObject<{
|
|
433
|
+
byTenant: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodNumber>;
|
|
434
|
+
count: import("zod").ZodNumber;
|
|
435
|
+
nextFireCount: import("zod").ZodNumber;
|
|
436
|
+
otherCount: import("zod").ZodNumber;
|
|
437
|
+
start: import("zod").ZodString;
|
|
438
|
+
}, import("zod/v4/core").$strip>>;
|
|
439
|
+
freshness: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
440
|
+
kind: import("zod").ZodLiteral<"authoritative">;
|
|
441
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
442
|
+
asOf: import("zod").ZodString;
|
|
443
|
+
kind: import("zod").ZodLiteral<"projected">;
|
|
444
|
+
lagSeconds: import("zod").ZodNumber;
|
|
445
|
+
}, import("zod/v4/core").$strip>], "kind">;
|
|
446
|
+
version: import("zod").ZodLiteral<"2026-08-09">;
|
|
447
|
+
}, import("zod/v4/core").$strip>;
|
|
358
448
|
export type ForecastWindows = z.infer<typeof forecastWindowsSchema>;
|
|
359
449
|
/**
|
|
360
450
|
* What the migrating consumer may rely on, published as data.
|
package/dist/forecast.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MAX_FORECAST_HORIZON_SECONDS } from "./configuration-bounds.js";
|
|
2
|
+
import { OPERATIONAL_TIMING } from "./operational-config.js";
|
|
3
|
+
import { z } from "./zod.js";
|
|
2
4
|
import { freshnessSchema, projectedFreshnessSchema, } from "./protocol.js";
|
|
3
5
|
import { timestampSchema } from "./time.js";
|
|
4
6
|
/**
|
|
@@ -55,10 +57,11 @@ export const FORECAST_BOUNDS = {
|
|
|
55
57
|
* argument for refusing rather than under-reporting collapses if staleness is
|
|
56
58
|
* the one degradation that gets through as a number.
|
|
57
59
|
*/
|
|
58
|
-
maxLagSeconds:
|
|
60
|
+
maxLagSeconds: (OPERATIONAL_TIMING.forecastRefreshMaximumMs * 2) / 1000,
|
|
59
61
|
/**
|
|
60
|
-
*
|
|
61
|
-
* the answer as short.
|
|
62
|
+
* Actual recurrence work units (shared cron advances or interval-series
|
|
63
|
+
* calculations) before a partition reports the answer as short. Output-cell
|
|
64
|
+
* allocation is bounded independently by maxGroupsPerPartition.
|
|
62
65
|
*
|
|
63
66
|
* Published rather than kept internal so a refusal is classifiable: a shadow
|
|
64
67
|
* comparison that sees a refusal needs to be able to tell "we are near a
|
|
@@ -75,7 +78,7 @@ export const FORECAST_BOUNDS = {
|
|
|
75
78
|
* legacy service's seven-day ceiling bounded the *query* with no snapshot
|
|
76
79
|
* behind it at all.
|
|
77
80
|
*/
|
|
78
|
-
maxWindowSeconds:
|
|
81
|
+
maxWindowSeconds: MAX_FORECAST_HORIZON_SECONDS,
|
|
79
82
|
minBucketSeconds: 60,
|
|
80
83
|
/**
|
|
81
84
|
* Longest a partition lets its snapshot stand when nothing has been written.
|
|
@@ -85,7 +88,7 @@ export const FORECAST_BOUNDS = {
|
|
|
85
88
|
* an incident. `freshness.lagSeconds` reports the actual age on every answer;
|
|
86
89
|
* this is the bound it lives inside.
|
|
87
90
|
*/
|
|
88
|
-
refreshCeilingSeconds:
|
|
91
|
+
refreshCeilingSeconds: OPERATIONAL_TIMING.forecastRefreshMaximumMs / 1000,
|
|
89
92
|
/**
|
|
90
93
|
* Shortest gap between refreshes once something *has* been written.
|
|
91
94
|
*
|
|
@@ -94,7 +97,7 @@ export const FORECAST_BOUNDS = {
|
|
|
94
97
|
* projection that rebuilt on every poll would be the cost this whole design
|
|
95
98
|
* exists to avoid.
|
|
96
99
|
*/
|
|
97
|
-
refreshFloorSeconds:
|
|
100
|
+
refreshFloorSeconds: OPERATIONAL_TIMING.forecastRefreshFloorMs / 1000,
|
|
98
101
|
/**
|
|
99
102
|
* How far below `now` a window may begin.
|
|
100
103
|
*
|
|
@@ -104,7 +107,7 @@ export const FORECAST_BOUNDS = {
|
|
|
104
107
|
* because the caller's `now` is a second behind. Further back than that is a
|
|
105
108
|
* question about the past, which a forecast does not answer.
|
|
106
109
|
*/
|
|
107
|
-
slackSeconds:
|
|
110
|
+
slackSeconds: OPERATIONAL_TIMING.forecastCoverageSlackMs / 1000,
|
|
108
111
|
/**
|
|
109
112
|
* Customer keys named individually in one bucket before the rest are summed.
|
|
110
113
|
*
|
|
@@ -337,7 +340,73 @@ export const forecastBucketSchema = z.object({
|
|
|
337
340
|
/** The bucket's epoch-aligned start. May precede the requested `from`. */
|
|
338
341
|
start: timestampSchema,
|
|
339
342
|
});
|
|
343
|
+
/** Capability opt-in prevents old clients that read only counts from mistaking
|
|
344
|
+
* a lower bound for complete work. Older servers safely ignore this header. */
|
|
345
|
+
export const FORECAST_PARTIAL_ACCEPT_HEADER = "X-Greatwait-Accept-Partial-Forecast";
|
|
346
|
+
export const forecastRequestHeadersSchema = z.object({
|
|
347
|
+
[FORECAST_PARTIAL_ACCEPT_HEADER]: z.literal("true").optional(),
|
|
348
|
+
});
|
|
349
|
+
export const forecastCoverageSchema = z
|
|
350
|
+
.object({
|
|
351
|
+
complete: z.boolean(),
|
|
352
|
+
countMeaning: z.enum(["complete-total", "lower-bound"]),
|
|
353
|
+
projectedWindow: z.object({ from: timestampSchema, to: timestampSchema }),
|
|
354
|
+
/** No interval after this can be assumed quiet from absent buckets. */
|
|
355
|
+
completeThrough: timestampSchema,
|
|
356
|
+
heads: z.object({
|
|
357
|
+
groupsRead: z.number().int().nonnegative(),
|
|
358
|
+
occurrencesCounted: z.number().int().nonnegative(),
|
|
359
|
+
complete: z.boolean(),
|
|
360
|
+
selection: z.literal("earliest bucket, latency class, partition key groups"),
|
|
361
|
+
lastGroup: z
|
|
362
|
+
.object({
|
|
363
|
+
start: timestampSchema,
|
|
364
|
+
latencyClass: z.enum(["realtime", "bulk"]),
|
|
365
|
+
partitionKey: z.string(),
|
|
366
|
+
})
|
|
367
|
+
.optional(),
|
|
368
|
+
}),
|
|
369
|
+
recurring: z.object({
|
|
370
|
+
schedulesRead: z.number().int().nonnegative(),
|
|
371
|
+
/** The selected population is complete, not necessarily its expansion. */
|
|
372
|
+
populationComplete: z.boolean(),
|
|
373
|
+
selection: z.literal("oldest eligible active recurring schedules by createdAt and scheduleId"),
|
|
374
|
+
firstScheduleId: z.string().optional(),
|
|
375
|
+
lastScheduleId: z.string().optional(),
|
|
376
|
+
}),
|
|
377
|
+
work: z.object({
|
|
378
|
+
usedUnits: z.number().int().nonnegative(),
|
|
379
|
+
limitUnits: z.number().int().nonnegative(),
|
|
380
|
+
}),
|
|
381
|
+
boundsReached: z.array(z.object({
|
|
382
|
+
kind: z.enum([
|
|
383
|
+
"head-cells",
|
|
384
|
+
"recurring-series",
|
|
385
|
+
"projection-work",
|
|
386
|
+
"projection-cells",
|
|
387
|
+
]),
|
|
388
|
+
limit: z.number().int().nonnegative(),
|
|
389
|
+
})),
|
|
390
|
+
})
|
|
391
|
+
.superRefine((coverage, context) => {
|
|
392
|
+
if ((coverage.countMeaning === "complete-total") !== coverage.complete ||
|
|
393
|
+
(coverage.complete &&
|
|
394
|
+
(coverage.boundsReached.length !== 0 ||
|
|
395
|
+
!coverage.heads.complete ||
|
|
396
|
+
!coverage.recurring.populationComplete ||
|
|
397
|
+
coverage.completeThrough !== coverage.projectedWindow.to)) ||
|
|
398
|
+
(!coverage.complete &&
|
|
399
|
+
(coverage.boundsReached.length === 0 ||
|
|
400
|
+
coverage.completeThrough !== coverage.projectedWindow.from))) {
|
|
401
|
+
context.addIssue({
|
|
402
|
+
code: "custom",
|
|
403
|
+
message: "Coverage must distinguish complete totals from lower bounds without claiming an unproven time prefix",
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
});
|
|
340
407
|
export const forecastSchema = z.object({
|
|
408
|
+
/** Optional for older servers and callers without the coverage capability. */
|
|
409
|
+
coverage: forecastCoverageSchema.optional(),
|
|
341
410
|
/** Ascending by `start`. A bucket with no occurrences is omitted. */
|
|
342
411
|
buckets: z.array(forecastBucketSchema),
|
|
343
412
|
/**
|
|
@@ -391,6 +460,10 @@ export function mergeForecastBuckets(buckets) {
|
|
|
391
460
|
}
|
|
392
461
|
into.count += bucket.count;
|
|
393
462
|
into.nextFireCount += bucket.nextFireCount;
|
|
463
|
+
if (bucket.omittedPartitionKeyCount !== undefined) {
|
|
464
|
+
into.omittedPartitionKeyCount =
|
|
465
|
+
(into.omittedPartitionKeyCount ?? 0) + bucket.omittedPartitionKeyCount;
|
|
466
|
+
}
|
|
394
467
|
into.unkeyedCount += bucket.unkeyedCount;
|
|
395
468
|
}
|
|
396
469
|
return [...merged.values()].sort((left, right) => left.bucketStartMs - right.bucketStartMs);
|
|
@@ -412,7 +485,7 @@ export function mergeForecastBuckets(buckets) {
|
|
|
412
485
|
export function topPartitionKeys(bucket) {
|
|
413
486
|
const ranked = Object.entries(bucket.byPartitionKey).sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]));
|
|
414
487
|
const byPartitionKey = Object.create(null);
|
|
415
|
-
let otherPartitionKeyCount = bucket.unkeyedCount;
|
|
488
|
+
let otherPartitionKeyCount = bucket.unkeyedCount + (bucket.omittedPartitionKeyCount ?? 0);
|
|
416
489
|
ranked.forEach(([key, n], index) => {
|
|
417
490
|
if (index < FORECAST_BOUNDS.topPartitionKeys) {
|
|
418
491
|
byPartitionKey[key] = n;
|
|
@@ -426,30 +499,20 @@ export function topPartitionKeys(bucket) {
|
|
|
426
499
|
/**
|
|
427
500
|
* Whether a gathered forecast may be published, and how old it is.
|
|
428
501
|
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
* bucket total and nothing else — not a degraded flag, not `freshness` — so a
|
|
433
|
-
* degraded answer reads to it as a quiet book, and a quiet book makes it
|
|
434
|
-
* release capacity. Its own failure path is fail-safe: a request that errors
|
|
435
|
-
* makes it hold its last good reading. So the honest degradation is the one
|
|
436
|
-
* that errors.
|
|
437
|
-
*
|
|
438
|
-
* The three are distinct because they mean different things to whoever is
|
|
439
|
-
* looking: a partition that did not answer is an availability problem, a book
|
|
440
|
-
* past the projection bound is a capacity problem with a published number
|
|
441
|
-
* beside it, and an answer older than the bound is a partition that has stopped
|
|
442
|
-
* refreshing.
|
|
502
|
+
* Unavailable and stale sources always refuse. Work-bound partial answers are
|
|
503
|
+
* permitted only for a reader that explicitly understands coverage; the
|
|
504
|
+
* default retains the count-only legacy consumer's safe failure behavior.
|
|
443
505
|
*
|
|
444
506
|
* `asOfMs` is the **oldest** across the shards, for the reason
|
|
445
507
|
* `projectionCoverage` takes the oldest checkpoint: one busy shard must not be
|
|
446
508
|
* allowed to vouch for three quiet ones.
|
|
447
509
|
*/
|
|
448
|
-
export function decideForecastAnswer(answers, nowMs) {
|
|
510
|
+
export function decideForecastAnswer(answers, nowMs, acceptPartial = false) {
|
|
449
511
|
if (answers.some((answer) => "refused" in answer)) {
|
|
450
512
|
return { ok: false, refusal: "partition-unavailable" };
|
|
451
513
|
}
|
|
452
|
-
if (
|
|
514
|
+
if (!acceptPartial &&
|
|
515
|
+
answers.some((answer) => "truncated" in answer && answer.truncated)) {
|
|
453
516
|
return { ok: false, refusal: "book-too-large" };
|
|
454
517
|
}
|
|
455
518
|
// **Only a partition that built a snapshot vouches for freshness.** One that
|
package/dist/identifiers.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
1
|
+
import { z } from "./zod.js";
|
|
2
2
|
/**
|
|
3
3
|
* Public identifiers.
|
|
4
4
|
*
|
|
@@ -37,25 +37,25 @@ export type IdResource = keyof typeof ID_PREFIXES;
|
|
|
37
37
|
export declare function idPattern(resource: IdResource): RegExp;
|
|
38
38
|
/** Any well-formed public identifier, whatever it names. */
|
|
39
39
|
export declare const ANY_ID_PATTERN: RegExp;
|
|
40
|
-
export declare function idSchema(resource: IdResource):
|
|
41
|
-
export declare const apiCredentialIdSchema:
|
|
42
|
-
export declare const apiCredentialEventIdSchema:
|
|
43
|
-
export declare const authorizationRequestIdSchema:
|
|
44
|
-
export declare const callbackSigningKeyIdSchema:
|
|
45
|
-
export declare const oauthClientIdSchema:
|
|
46
|
-
export declare const oauthGrantIdSchema:
|
|
47
|
-
export declare const oauthGrantEventIdSchema:
|
|
48
|
-
export declare const scheduleIdSchema:
|
|
49
|
-
export declare const occurrenceIdSchema:
|
|
50
|
-
export declare const attemptIdSchema:
|
|
51
|
-
export declare const deliveryIdSchema:
|
|
52
|
-
export declare const endpointIdSchema:
|
|
53
|
-
export declare const organizationIdSchema:
|
|
54
|
-
export declare const projectIdSchema:
|
|
55
|
-
export declare const environmentIdSchema:
|
|
56
|
-
export declare const eventIdSchema:
|
|
57
|
-
export declare const testSinkIdSchema:
|
|
58
|
-
export declare const testSinkDeliveryIdSchema:
|
|
40
|
+
export declare function idSchema(resource: IdResource): import("zod").ZodString;
|
|
41
|
+
export declare const apiCredentialIdSchema: import("zod").ZodString;
|
|
42
|
+
export declare const apiCredentialEventIdSchema: import("zod").ZodString;
|
|
43
|
+
export declare const authorizationRequestIdSchema: import("zod").ZodString;
|
|
44
|
+
export declare const callbackSigningKeyIdSchema: import("zod").ZodString;
|
|
45
|
+
export declare const oauthClientIdSchema: import("zod").ZodString;
|
|
46
|
+
export declare const oauthGrantIdSchema: import("zod").ZodString;
|
|
47
|
+
export declare const oauthGrantEventIdSchema: import("zod").ZodString;
|
|
48
|
+
export declare const scheduleIdSchema: import("zod").ZodString;
|
|
49
|
+
export declare const occurrenceIdSchema: import("zod").ZodString;
|
|
50
|
+
export declare const attemptIdSchema: import("zod").ZodString;
|
|
51
|
+
export declare const deliveryIdSchema: import("zod").ZodString;
|
|
52
|
+
export declare const endpointIdSchema: import("zod").ZodString;
|
|
53
|
+
export declare const organizationIdSchema: import("zod").ZodString;
|
|
54
|
+
export declare const projectIdSchema: import("zod").ZodString;
|
|
55
|
+
export declare const environmentIdSchema: import("zod").ZodString;
|
|
56
|
+
export declare const eventIdSchema: import("zod").ZodString;
|
|
57
|
+
export declare const testSinkIdSchema: import("zod").ZodString;
|
|
58
|
+
export declare const testSinkDeliveryIdSchema: import("zod").ZodString;
|
|
59
59
|
export type ApiCredentialId = z.infer<typeof apiCredentialIdSchema>;
|
|
60
60
|
export type ApiCredentialEventId = z.infer<typeof apiCredentialEventIdSchema>;
|
|
61
61
|
export type AuthorizationRequestId = z.infer<typeof authorizationRequestIdSchema>;
|
package/dist/identifiers.js
CHANGED