@greatwait/contracts 0.1.0-alpha.2 → 0.1.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/dist/authority.d.ts +84 -21
- package/dist/authority.js +47 -2
- package/dist/billing.d.ts +1001 -0
- package/dist/billing.js +684 -0
- package/dist/callback-safety.d.ts +2 -2
- package/dist/callback-safety.js +2 -2
- package/dist/compatibility.d.ts +3 -3
- package/dist/compatibility.js +1 -1
- package/dist/data-export.d.ts +67 -0
- package/dist/data-export.js +182 -0
- package/dist/endpoints.d.ts +181 -240
- package/dist/endpoints.js +77 -81
- package/dist/events.d.ts +17 -17
- package/dist/events.js +1 -1
- package/dist/first-value-journey.d.ts +192 -42
- package/dist/first-value-journey.js +212 -6
- package/dist/forecast.d.ts +71 -71
- package/dist/forecast.js +1 -1
- package/dist/identifiers.d.ts +20 -20
- package/dist/identifiers.js +1 -1
- package/dist/identity.d.ts +45 -41
- package/dist/identity.js +5 -4
- package/dist/index.d.ts +13 -8
- package/dist/index.js +13 -8
- package/dist/mcp.d.ts +201 -0
- package/dist/mcp.js +214 -0
- package/dist/naming.d.ts +45 -0
- package/dist/naming.js +159 -0
- package/dist/oauth.d.ts +186 -172
- package/dist/oauth.js +84 -8
- package/dist/operation-definitions.d.ts +9 -0
- package/dist/operation-definitions.js +7 -0
- package/dist/operations.d.ts +4359 -2214
- package/dist/operations.js +2754 -881
- package/dist/organization-lifecycle.d.ts +34 -0
- package/dist/organization-lifecycle.js +122 -0
- package/dist/partition.d.ts +26 -0
- package/dist/policy.d.ts +4 -4
- package/dist/policy.js +9 -5
- package/dist/problems.d.ts +32 -26
- package/dist/problems.js +6 -2
- package/dist/protocol.d.ts +204 -75
- package/dist/protocol.js +108 -36
- package/dist/scheduling-records.d.ts +343 -285
- package/dist/scheduling-records.js +1 -1
- package/dist/scheduling.d.ts +670 -360
- package/dist/scheduling.js +382 -56
- 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 +197 -31
- 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 +4 -0
- package/generated/v1/examples/attempts.read.response.json +4 -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.fundingquote.request.json +7 -0
- package/generated/v1/examples/billing.fundingquote.response.json +13 -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.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/context.read.response.json +6 -0
- package/generated/v1/examples/credentials.connection.response.json +16 -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/occurrences.read.response.json +4 -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 +19 -10
- package/generated/v1/manifest.json +1019 -53
- package/generated/v1/openapi.json +30597 -5709
- package/generated/v1/policy-matrix.json +290 -45
- package/generated/v1/schemas/attempts.list.response.json +24 -1
- package/generated/v1/schemas/attempts.read.response.json +24 -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.fundingquote.request.json +28 -0
- package/generated/v1/schemas/billing.fundingquote.response.json +61 -0
- package/generated/v1/schemas/billing.ledger.query.json +16 -0
- package/generated/v1/schemas/billing.ledger.response.json +125 -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 +36 -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.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 +22 -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 +45 -0
- package/generated/v1/schemas/credentials.connection.response.json +66 -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/grants.list.response.json +2 -0
- package/generated/v1/schemas/grants.revoke.response.json +2 -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 +24 -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/attempts.list.json +1 -0
- package/generated/v1/snippets/attempts.read.json +1 -0
- 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.fundingquote.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.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/context.read.json +6 -0
- package/generated/v1/snippets/credentials.connection.json +6 -0
- package/generated/v1/snippets/credentials.create.json +1 -0
- package/generated/v1/snippets/credentials.list.json +1 -0
- package/generated/v1/snippets/credentials.revoke.json +1 -0
- package/generated/v1/snippets/credentials.rotate.json +1 -0
- package/generated/v1/snippets/endpoints.acknowledgeSigningKeyRotation.json +6 -0
- package/generated/v1/snippets/endpoints.create.json +1 -0
- package/generated/v1/snippets/endpoints.disable.json +1 -0
- package/generated/v1/snippets/{endpoints.verify.json → endpoints.enable.json} +4 -3
- package/generated/v1/snippets/endpoints.list.json +1 -0
- package/generated/v1/snippets/endpoints.read.json +1 -0
- package/generated/v1/snippets/endpoints.revealSigningSecret.json +6 -0
- package/generated/v1/snippets/endpoints.rotateSigningKey.json +1 -0
- package/generated/v1/snippets/endpoints.update.json +1 -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.read.json +1 -0
- package/generated/v1/snippets/forecast.windows.json +1 -0
- package/generated/v1/snippets/grants.list.json +1 -0
- package/generated/v1/snippets/grants.revoke.json +1 -0
- package/generated/v1/snippets/journey/await-occurrence.json +6 -0
- package/generated/v1/snippets/journey/check-credential.json +6 -0
- package/generated/v1/snippets/journey/check-service.json +6 -0
- package/generated/v1/snippets/journey/clean-up.json +6 -0
- package/generated/v1/snippets/journey/create-destination.json +6 -0
- package/generated/v1/snippets/journey/create-one-shot.json +6 -0
- package/generated/v1/snippets/journey/read-attempt.json +6 -0
- package/generated/v1/snippets/journey/read-schedule.json +6 -0
- package/generated/v1/snippets/journey/replay-one-shot.json +6 -0
- package/generated/v1/snippets/meta.scaffold.json +1 -0
- package/generated/v1/snippets/meta.version.json +1 -0
- package/generated/v1/snippets/occurrences.list.json +1 -0
- package/generated/v1/snippets/occurrences.read.json +1 -0
- package/generated/v1/snippets/occurrences.redeliver.json +1 -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.create.json +1 -0
- package/generated/v1/snippets/projects.delete.json +6 -0
- package/generated/v1/snippets/projects.list.json +1 -0
- package/generated/v1/snippets/projects.rename.json +6 -0
- package/generated/v1/snippets/schedules.archive.json +1 -0
- package/generated/v1/snippets/schedules.cancel.json +1 -0
- package/generated/v1/snippets/schedules.create.json +4 -3
- package/generated/v1/snippets/schedules.list.json +1 -0
- package/generated/v1/snippets/schedules.pause.json +1 -0
- package/generated/v1/snippets/schedules.read.json +1 -0
- package/generated/v1/snippets/schedules.replace.json +4 -3
- package/generated/v1/snippets/schedules.resume.json +1 -0
- package/generated/v1/snippets/sinkdeliveries.list.json +1 -0
- package/generated/v1/snippets/sinkdeliveries.read.json +1 -0
- package/generated/v1/snippets/testsinks.configure.json +1 -0
- package/generated/v1/snippets/testsinks.create.json +1 -0
- package/generated/v1/snippets/testsinks.delete.json +1 -0
- package/generated/v1/snippets/testsinks.list.json +1 -0
- package/generated/v1/snippets/testsinks.read.json +1 -0
- package/generated/v1/snippets/timing.summary.json +6 -0
- package/generated/v1/snippets/usage.read.json +1 -0
- package/package.json +2 -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/protocol.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
1
|
+
import { z } from "./zod.js";
|
|
2
2
|
import type { Authority } from "./authority.js";
|
|
3
3
|
import type { FieldError } from "./problems.js";
|
|
4
4
|
/**
|
|
@@ -15,11 +15,74 @@ export declare const PAGE_SIZE: {
|
|
|
15
15
|
readonly max: 100;
|
|
16
16
|
readonly min: 1;
|
|
17
17
|
};
|
|
18
|
-
export declare const pageRequestSchema:
|
|
19
|
-
cursor:
|
|
20
|
-
limit:
|
|
21
|
-
},
|
|
18
|
+
export declare const pageRequestSchema: import("zod").ZodObject<{
|
|
19
|
+
cursor: import("zod").ZodOptional<import("zod").ZodString>;
|
|
20
|
+
limit: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
21
|
+
}, import("zod/v4/core").$strip>;
|
|
22
22
|
export type PageRequest = z.infer<typeof pageRequestSchema>;
|
|
23
|
+
/**
|
|
24
|
+
* A schedules listing: the page, and optionally one endpoint to keep to.
|
|
25
|
+
*
|
|
26
|
+
* The way back from a destination to everything pointed at it. Somebody who
|
|
27
|
+
* disabled an endpoint by mistake, or is about to move one, has to be able to
|
|
28
|
+
* see the schedules that deliver to it without reading the whole project.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* How a schedules listing may be ordered.
|
|
32
|
+
*
|
|
33
|
+
* `created` is the order this listing has always had and keeps by default, so a
|
|
34
|
+
* client that never heard of this parameter sees nothing change. `due` is what
|
|
35
|
+
* somebody looking at a list of schedules wants (FXO-2283) — what fires next,
|
|
36
|
+
* first — and it is a different index rather than a sort of the page, because
|
|
37
|
+
* sorting a page would order a hundred rows the cursor had already chosen by
|
|
38
|
+
* creation instant.
|
|
39
|
+
*/
|
|
40
|
+
export declare const SCHEDULE_ORDERS: readonly ["created", "due"];
|
|
41
|
+
export type ScheduleOrder = (typeof SCHEDULE_ORDERS)[number];
|
|
42
|
+
/**
|
|
43
|
+
* A schedules listing: the page, optionally one endpoint, and how to order it.
|
|
44
|
+
*
|
|
45
|
+
* The way back from a destination to everything pointed at it. Somebody who
|
|
46
|
+
* disabled an endpoint by mistake, or is about to move one, has to be able to
|
|
47
|
+
* see the schedules that deliver to it without reading the whole project.
|
|
48
|
+
*
|
|
49
|
+
* `dueBefore` filters on the earliest unsettled occurrence. It is served by the
|
|
50
|
+
* same index `order=due` walks, so filtering and ordering cost the same probe;
|
|
51
|
+
* a schedule with nothing on the books matches no `dueBefore`, because it has
|
|
52
|
+
* no instant to compare and inventing one either way would be a guess.
|
|
53
|
+
*/
|
|
54
|
+
export declare const scheduleListRequestSchema: import("zod").ZodObject<{
|
|
55
|
+
cursor: import("zod").ZodOptional<import("zod").ZodString>;
|
|
56
|
+
limit: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
57
|
+
dueBefore: import("zod").ZodOptional<import("zod").ZodString>;
|
|
58
|
+
endpoint: import("zod").ZodOptional<import("zod").ZodString>;
|
|
59
|
+
order: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
60
|
+
created: "created";
|
|
61
|
+
due: "due";
|
|
62
|
+
}>>;
|
|
63
|
+
}, import("zod/v4/core").$strip>;
|
|
64
|
+
export type ScheduleListRequest = z.infer<typeof scheduleListRequestSchema>;
|
|
65
|
+
/**
|
|
66
|
+
* Which end of a history a page walks from.
|
|
67
|
+
*
|
|
68
|
+
* `oldest` is the order every listing has always had and keeps by default; a
|
|
69
|
+
* client that never heard of this parameter sees nothing change. `newest` is
|
|
70
|
+
* what a person looking at a schedule wants (FXO-2259): what happened most
|
|
71
|
+
* recently, first — and on a schedule firing every five minutes for thirty
|
|
72
|
+
* days that is eight thousand rows away from the other end.
|
|
73
|
+
*/
|
|
74
|
+
export declare const HISTORY_ORDERS: readonly ["oldest", "newest"];
|
|
75
|
+
export type HistoryOrder = (typeof HISTORY_ORDERS)[number];
|
|
76
|
+
/** A page request over a history, which may be walked from either end. */
|
|
77
|
+
export declare const historyPageRequestSchema: import("zod").ZodObject<{
|
|
78
|
+
cursor: import("zod").ZodOptional<import("zod").ZodString>;
|
|
79
|
+
limit: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
80
|
+
order: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
81
|
+
oldest: "oldest";
|
|
82
|
+
newest: "newest";
|
|
83
|
+
}>>;
|
|
84
|
+
}, import("zod/v4/core").$strip>;
|
|
85
|
+
export type HistoryPageRequest = z.infer<typeof historyPageRequestSchema>;
|
|
23
86
|
/**
|
|
24
87
|
* A page of results.
|
|
25
88
|
*
|
|
@@ -29,13 +92,13 @@ export type PageRequest = z.infer<typeof pageRequestSchema>;
|
|
|
29
92
|
* stale data as fact. `authoritative` means the answer came from the owning
|
|
30
93
|
* partition; `projected` means it may lag and carries the age.
|
|
31
94
|
*/
|
|
32
|
-
export declare const freshnessSchema:
|
|
33
|
-
kind:
|
|
34
|
-
},
|
|
35
|
-
asOf:
|
|
36
|
-
kind:
|
|
37
|
-
lagSeconds:
|
|
38
|
-
},
|
|
95
|
+
export declare const freshnessSchema: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
96
|
+
kind: import("zod").ZodLiteral<"authoritative">;
|
|
97
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
98
|
+
asOf: import("zod").ZodString;
|
|
99
|
+
kind: import("zod").ZodLiteral<"projected">;
|
|
100
|
+
lagSeconds: import("zod").ZodNumber;
|
|
101
|
+
}, import("zod/v4/core").$strip>], "kind">;
|
|
39
102
|
export type Freshness = z.infer<typeof freshnessSchema>;
|
|
40
103
|
/**
|
|
41
104
|
* The `projected` arm alone, for a response that is never authoritative.
|
|
@@ -47,37 +110,74 @@ export type Freshness = z.infer<typeof freshnessSchema>;
|
|
|
47
110
|
* taken, were unreachable without narrowing that no consumer could justify.
|
|
48
111
|
* Naming the narrower shape moves the claim into the type.
|
|
49
112
|
*/
|
|
50
|
-
export declare const projectedFreshnessSchema:
|
|
51
|
-
asOf:
|
|
52
|
-
kind:
|
|
53
|
-
lagSeconds:
|
|
54
|
-
},
|
|
113
|
+
export declare const projectedFreshnessSchema: import("zod").ZodObject<{
|
|
114
|
+
asOf: import("zod").ZodString;
|
|
115
|
+
kind: import("zod").ZodLiteral<"projected">;
|
|
116
|
+
lagSeconds: import("zod").ZodNumber;
|
|
117
|
+
}, import("zod/v4/core").$strip>;
|
|
55
118
|
export type ProjectedFreshness = z.infer<typeof projectedFreshnessSchema>;
|
|
56
|
-
export declare function pageSchema<TItem extends z.ZodTypeAny>(item: TItem):
|
|
57
|
-
data:
|
|
58
|
-
freshness:
|
|
59
|
-
kind:
|
|
60
|
-
},
|
|
61
|
-
asOf:
|
|
62
|
-
kind:
|
|
63
|
-
lagSeconds:
|
|
64
|
-
},
|
|
65
|
-
nextCursor:
|
|
66
|
-
},
|
|
119
|
+
export declare function pageSchema<TItem extends z.ZodTypeAny>(item: TItem): import("zod").ZodObject<{
|
|
120
|
+
data: import("zod").ZodArray<TItem>;
|
|
121
|
+
freshness: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
122
|
+
kind: import("zod").ZodLiteral<"authoritative">;
|
|
123
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
124
|
+
asOf: import("zod").ZodString;
|
|
125
|
+
kind: import("zod").ZodLiteral<"projected">;
|
|
126
|
+
lagSeconds: import("zod").ZodNumber;
|
|
127
|
+
}, import("zod/v4/core").$strip>], "kind">;
|
|
128
|
+
nextCursor: import("zod").ZodOptional<import("zod").ZodString>;
|
|
129
|
+
}, import("zod/v4/core").$strip>;
|
|
67
130
|
/**
|
|
68
131
|
* Where a page stopped.
|
|
69
132
|
*
|
|
70
|
-
* Every collection in this product is ordered by
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
133
|
+
* Every collection in this product is ordered by one timestamp and then by its
|
|
134
|
+
* identifier, so one position type serves all of them. Most use creation time;
|
|
135
|
+
* schedules ordered by next due use that due instant, and the project execution
|
|
136
|
+
* index uses the occurrence's planned instant. The identifier is the tiebreak
|
|
137
|
+
* rather than decoration: two occurrences planned for the same millisecond are
|
|
138
|
+
* ordinary, and an order that does not break the tie can show one of them twice
|
|
139
|
+
* and the other never.
|
|
75
140
|
*/
|
|
76
141
|
export interface PagePosition {
|
|
77
|
-
/**
|
|
142
|
+
/**
|
|
143
|
+
* The ordering instant of the last item served. The historical property name
|
|
144
|
+
* remains for wire and adapter compatibility; see the type comment above.
|
|
145
|
+
*/
|
|
78
146
|
readonly createdAtMs: number;
|
|
79
147
|
/** That item's identifier. */
|
|
80
148
|
readonly id: string;
|
|
149
|
+
/**
|
|
150
|
+
* The order the page was walked in, for a listing that has more than one
|
|
151
|
+
* (FXO-2259, FXO-2283). A position is only a position in the order that
|
|
152
|
+
* issued it: presented under another, it is refused rather than resumed from
|
|
153
|
+
* the middle of the book in the wrong direction. Absent on the listings that
|
|
154
|
+
* have one order, and on cursors issued before this field.
|
|
155
|
+
*
|
|
156
|
+
* **Two vocabularies, deliberately, because they are two different
|
|
157
|
+
* questions.** A history is walked from an end — `oldest` or `newest` — and a
|
|
158
|
+
* schedules listing is ordered by a *field*: `created` or `due`. Collapsing
|
|
159
|
+
* them into one enum would let a history cursor and a schedules cursor
|
|
160
|
+
* compare equal, which is the comparison this field exists to make impossible.
|
|
161
|
+
* A cursor carries whichever its listing issued, and the two listings never
|
|
162
|
+
* read each other's.
|
|
163
|
+
*/
|
|
164
|
+
readonly order?: "created" | "due" | "newest" | "oldest";
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* The collection and filters under which a cursor was issued.
|
|
168
|
+
*
|
|
169
|
+
* A position is meaningful only inside the exact listing that produced it.
|
|
170
|
+
* Authority already keeps it inside one tenant; this binding keeps a cursor
|
|
171
|
+
* from one collection, or from one filtered view of a collection, from being
|
|
172
|
+
* replayed into another and silently resuming at an unrelated position.
|
|
173
|
+
*
|
|
174
|
+
* Parameters are a record rather than an encoded string so normalization has
|
|
175
|
+
* one home here. Their names are sorted before encoding; callers may build the
|
|
176
|
+
* object in any order and still mint the same binding.
|
|
177
|
+
*/
|
|
178
|
+
export interface CursorBinding {
|
|
179
|
+
readonly operation: string;
|
|
180
|
+
readonly parameters?: Readonly<Record<string, string>>;
|
|
81
181
|
}
|
|
82
182
|
/**
|
|
83
183
|
* The cursor a client is handed for the next page.
|
|
@@ -88,7 +188,7 @@ export interface PagePosition {
|
|
|
88
188
|
* carries authority, and it carries none — every listing is scoped by the
|
|
89
189
|
* principal before a cursor is even looked at.
|
|
90
190
|
*/
|
|
91
|
-
export declare function encodeCursor(authority: Authority, position: PagePosition): string;
|
|
191
|
+
export declare function encodeCursor(authority: Authority, position: PagePosition, binding?: CursorBinding): string;
|
|
92
192
|
/**
|
|
93
193
|
* The position a cursor names, or nothing.
|
|
94
194
|
*
|
|
@@ -98,7 +198,7 @@ export declare function encodeCursor(authority: Authority, position: PagePositio
|
|
|
98
198
|
* their cursor is wrong tells them what a valid one looks like, and the caller
|
|
99
199
|
* never constructs one anyway.
|
|
100
200
|
*/
|
|
101
|
-
export declare function decodeCursor(authority: Authority, cursor: string): PagePosition | undefined;
|
|
201
|
+
export declare function decodeCursor(authority: Authority, cursor: string, binding?: CursorBinding): PagePosition | undefined;
|
|
102
202
|
export type PageRequestParse = {
|
|
103
203
|
readonly ok: true;
|
|
104
204
|
readonly page: PageRequest;
|
|
@@ -122,13 +222,31 @@ export type PageRequestParse = {
|
|
|
122
222
|
* is the direction compatibility has to hold in.
|
|
123
223
|
*/
|
|
124
224
|
export declare function parsePageRequest(query: URLSearchParams): PageRequestParse;
|
|
225
|
+
export type ScheduleListRequestParse = {
|
|
226
|
+
readonly ok: true;
|
|
227
|
+
readonly page: ScheduleListRequest;
|
|
228
|
+
} | {
|
|
229
|
+
readonly ok: false;
|
|
230
|
+
readonly errors: readonly FieldError[];
|
|
231
|
+
};
|
|
232
|
+
/** A schedules listing request: the page, and the endpoint filter if given. */
|
|
233
|
+
export declare function parseScheduleListRequest(query: URLSearchParams): ScheduleListRequestParse;
|
|
234
|
+
export type HistoryPageRequestParse = {
|
|
235
|
+
readonly ok: true;
|
|
236
|
+
readonly page: HistoryPageRequest;
|
|
237
|
+
} | {
|
|
238
|
+
readonly ok: false;
|
|
239
|
+
readonly errors: readonly FieldError[];
|
|
240
|
+
};
|
|
241
|
+
/** A history page request: the page, and which end it walks from. */
|
|
242
|
+
export declare function parseHistoryPageRequest(query: URLSearchParams): HistoryPageRequestParse;
|
|
125
243
|
/**
|
|
126
244
|
* Every mutable resource carries a monotonically increasing `version`, surfaced
|
|
127
245
|
* as a strong ETag. A conditional write that loses the race is refused with
|
|
128
246
|
* `version_conflict` rather than silently overwriting — a cancel racing a
|
|
129
247
|
* replace must not resolve by luck.
|
|
130
248
|
*/
|
|
131
|
-
export declare const versionSchema:
|
|
249
|
+
export declare const versionSchema: import("zod").ZodNumber;
|
|
132
250
|
export type Version = z.infer<typeof versionSchema>;
|
|
133
251
|
export declare function toETag(version: Version): string;
|
|
134
252
|
/** Parses a strong ETag, returning undefined for anything malformed or weak. */
|
|
@@ -143,7 +261,7 @@ export declare function fromETag(etag: string): Version | undefined;
|
|
|
143
261
|
* refinement is the extra strictness the OpenAPI preamble already discloses
|
|
144
262
|
* that a described schema does not capture.
|
|
145
263
|
*/
|
|
146
|
-
export declare const etagSchema:
|
|
264
|
+
export declare const etagSchema: import("zod").ZodString;
|
|
147
265
|
/**
|
|
148
266
|
* Idempotency keys make an unsafe write safe to retry.
|
|
149
267
|
*
|
|
@@ -154,7 +272,7 @@ export declare const etagSchema: z.ZodString;
|
|
|
154
272
|
* silent second write — that distinction is the whole point, and the legacy
|
|
155
273
|
* scheduler had no equivalent.
|
|
156
274
|
*/
|
|
157
|
-
export declare const idempotencyKeySchema:
|
|
275
|
+
export declare const idempotencyKeySchema: import("zod").ZodString;
|
|
158
276
|
export type IdempotencyKey = z.infer<typeof idempotencyKeySchema>;
|
|
159
277
|
/**
|
|
160
278
|
* The scope a key was used in. Carried on the receipt rather than assumed,
|
|
@@ -163,24 +281,24 @@ export type IdempotencyKey = z.infer<typeof idempotencyKeySchema>;
|
|
|
163
281
|
* send the same key. The scope is part of the record so that mistake cannot be
|
|
164
282
|
* made silently.
|
|
165
283
|
*/
|
|
166
|
-
export declare const idempotencyScopeSchema:
|
|
167
|
-
environment:
|
|
168
|
-
operation:
|
|
169
|
-
organization:
|
|
170
|
-
project:
|
|
171
|
-
},
|
|
284
|
+
export declare const idempotencyScopeSchema: import("zod").ZodObject<{
|
|
285
|
+
environment: import("zod").ZodString;
|
|
286
|
+
operation: import("zod").ZodString;
|
|
287
|
+
organization: import("zod").ZodString;
|
|
288
|
+
project: import("zod").ZodString;
|
|
289
|
+
}, import("zod/v4/core").$strip>;
|
|
172
290
|
export type IdempotencyScope = z.infer<typeof idempotencyScopeSchema>;
|
|
173
|
-
export declare const idempotencyReceiptSchema:
|
|
174
|
-
requestFingerprint:
|
|
175
|
-
replayed:
|
|
176
|
-
scope:
|
|
177
|
-
environment:
|
|
178
|
-
operation:
|
|
179
|
-
organization:
|
|
180
|
-
project:
|
|
181
|
-
},
|
|
182
|
-
storedAt:
|
|
183
|
-
},
|
|
291
|
+
export declare const idempotencyReceiptSchema: import("zod").ZodObject<{
|
|
292
|
+
requestFingerprint: import("zod").ZodString;
|
|
293
|
+
replayed: import("zod").ZodBoolean;
|
|
294
|
+
scope: import("zod").ZodObject<{
|
|
295
|
+
environment: import("zod").ZodString;
|
|
296
|
+
operation: import("zod").ZodString;
|
|
297
|
+
organization: import("zod").ZodString;
|
|
298
|
+
project: import("zod").ZodString;
|
|
299
|
+
}, import("zod/v4/core").$strip>;
|
|
300
|
+
storedAt: import("zod").ZodString;
|
|
301
|
+
}, import("zod/v4/core").$strip>;
|
|
184
302
|
export type IdempotencyReceipt = z.infer<typeof idempotencyReceiptSchema>;
|
|
185
303
|
/**
|
|
186
304
|
* The canonical form of a request, as the receipt's `requestFingerprint`
|
|
@@ -256,9 +374,9 @@ export declare const CONCURRENCY_HEADERS: {
|
|
|
256
374
|
readonly ifMatch: "If-Match";
|
|
257
375
|
readonly replayed: "Idempotency-Replayed";
|
|
258
376
|
};
|
|
259
|
-
export declare const idempotencyRequestHeaderSchema:
|
|
260
|
-
"Idempotency-Key":
|
|
261
|
-
},
|
|
377
|
+
export declare const idempotencyRequestHeaderSchema: import("zod").ZodObject<{
|
|
378
|
+
"Idempotency-Key": import("zod").ZodOptional<import("zod").ZodString>;
|
|
379
|
+
}, import("zod/v4/core").$strip>;
|
|
262
380
|
/**
|
|
263
381
|
* A write for which idempotency is mandatory, rather than an optional
|
|
264
382
|
* protection a caller may opt into.
|
|
@@ -268,21 +386,32 @@ export declare const idempotencyRequestHeaderSchema: z.ZodObject<{
|
|
|
268
386
|
* `idempotencyRequestHeaderSchema` lets schedule creation retain its published
|
|
269
387
|
* optional behavior without weakening the redelivery promise.
|
|
270
388
|
*/
|
|
271
|
-
export declare const requiredIdempotencyRequestHeaderSchema:
|
|
272
|
-
"Idempotency-Key":
|
|
273
|
-
},
|
|
274
|
-
export declare const conditionalRequestHeaderSchema:
|
|
275
|
-
"If-Match":
|
|
276
|
-
},
|
|
389
|
+
export declare const requiredIdempotencyRequestHeaderSchema: import("zod").ZodObject<{
|
|
390
|
+
"Idempotency-Key": import("zod").ZodString;
|
|
391
|
+
}, import("zod/v4/core").$strip>;
|
|
392
|
+
export declare const conditionalRequestHeaderSchema: import("zod").ZodObject<{
|
|
393
|
+
"If-Match": import("zod").ZodOptional<import("zod").ZodString>;
|
|
394
|
+
}, import("zod/v4/core").$strip>;
|
|
395
|
+
/**
|
|
396
|
+
* A conditional write that refuses an unversioned request.
|
|
397
|
+
*
|
|
398
|
+
* Project lifecycle changes use this stricter shape because rename, archive,
|
|
399
|
+
* restore and permanent deletion are management actions over one shared row:
|
|
400
|
+
* silently accepting a missing precondition would let a stale General page
|
|
401
|
+
* overwrite a newer decision.
|
|
402
|
+
*/
|
|
403
|
+
export declare const requiredConditionalRequestHeaderSchema: import("zod").ZodObject<{
|
|
404
|
+
"If-Match": import("zod").ZodString;
|
|
405
|
+
}, import("zod/v4/core").$strip>;
|
|
277
406
|
/**
|
|
278
407
|
* Required rather than optional, deliberately: an operation that declares this
|
|
279
408
|
* promises the header on every success, and a client that has to test for its
|
|
280
409
|
* presence before making a conditional write will write the untested branch
|
|
281
410
|
* wrong.
|
|
282
411
|
*/
|
|
283
|
-
export declare const versionResponseHeaderSchema:
|
|
284
|
-
ETag:
|
|
285
|
-
},
|
|
412
|
+
export declare const versionResponseHeaderSchema: import("zod").ZodObject<{
|
|
413
|
+
ETag: import("zod").ZodString;
|
|
414
|
+
}, import("zod/v4/core").$strip>;
|
|
286
415
|
/**
|
|
287
416
|
* What a replayed write answers with, on top of the version.
|
|
288
417
|
*
|
|
@@ -298,11 +427,11 @@ export declare const versionResponseHeaderSchema: z.ZodObject<{
|
|
|
298
427
|
* header is the ordinary case, and a client that has to read a header to learn
|
|
299
428
|
* nothing happened is a client that will not read it.
|
|
300
429
|
*/
|
|
301
|
-
export declare const replayedResponseHeaderSchema:
|
|
302
|
-
ETag:
|
|
303
|
-
"Idempotency-Replayed":
|
|
304
|
-
},
|
|
430
|
+
export declare const replayedResponseHeaderSchema: import("zod").ZodObject<{
|
|
431
|
+
ETag: import("zod").ZodString;
|
|
432
|
+
"Idempotency-Replayed": import("zod").ZodOptional<import("zod").ZodLiteral<"true">>;
|
|
433
|
+
}, import("zod/v4/core").$strip>;
|
|
305
434
|
/** Replay marker for an idempotent create whose result has no ETag. */
|
|
306
|
-
export declare const idempotencyReplayResponseHeaderSchema:
|
|
307
|
-
"Idempotency-Replayed":
|
|
308
|
-
},
|
|
435
|
+
export declare const idempotencyReplayResponseHeaderSchema: import("zod").ZodObject<{
|
|
436
|
+
"Idempotency-Replayed": import("zod").ZodOptional<import("zod").ZodLiteral<"true">>;
|
|
437
|
+
}, import("zod/v4/core").$strip>;
|
package/dist/protocol.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { environmentIdSchema, organizationIdSchema, projectIdSchema, } from "./identifiers.js";
|
|
1
|
+
import { z } from "./zod.js";
|
|
2
|
+
import { endpointIdSchema, environmentIdSchema, organizationIdSchema, projectIdSchema, } from "./identifiers.js";
|
|
3
3
|
import { timestampSchema } from "./time.js";
|
|
4
4
|
/**
|
|
5
5
|
* Request and collection mechanics: paging, optimistic concurrency, and
|
|
@@ -23,6 +23,55 @@ export const pageRequestSchema = z.object({
|
|
|
23
23
|
.max(PAGE_SIZE.max)
|
|
24
24
|
.default(PAGE_SIZE.default),
|
|
25
25
|
});
|
|
26
|
+
/**
|
|
27
|
+
* A schedules listing: the page, and optionally one endpoint to keep to.
|
|
28
|
+
*
|
|
29
|
+
* The way back from a destination to everything pointed at it. Somebody who
|
|
30
|
+
* disabled an endpoint by mistake, or is about to move one, has to be able to
|
|
31
|
+
* see the schedules that deliver to it without reading the whole project.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* How a schedules listing may be ordered.
|
|
35
|
+
*
|
|
36
|
+
* `created` is the order this listing has always had and keeps by default, so a
|
|
37
|
+
* client that never heard of this parameter sees nothing change. `due` is what
|
|
38
|
+
* somebody looking at a list of schedules wants (FXO-2283) — what fires next,
|
|
39
|
+
* first — and it is a different index rather than a sort of the page, because
|
|
40
|
+
* sorting a page would order a hundred rows the cursor had already chosen by
|
|
41
|
+
* creation instant.
|
|
42
|
+
*/
|
|
43
|
+
export const SCHEDULE_ORDERS = ["created", "due"];
|
|
44
|
+
/**
|
|
45
|
+
* A schedules listing: the page, optionally one endpoint, and how to order it.
|
|
46
|
+
*
|
|
47
|
+
* The way back from a destination to everything pointed at it. Somebody who
|
|
48
|
+
* disabled an endpoint by mistake, or is about to move one, has to be able to
|
|
49
|
+
* see the schedules that deliver to it without reading the whole project.
|
|
50
|
+
*
|
|
51
|
+
* `dueBefore` filters on the earliest unsettled occurrence. It is served by the
|
|
52
|
+
* same index `order=due` walks, so filtering and ordering cost the same probe;
|
|
53
|
+
* a schedule with nothing on the books matches no `dueBefore`, because it has
|
|
54
|
+
* no instant to compare and inventing one either way would be a guess.
|
|
55
|
+
*/
|
|
56
|
+
export const scheduleListRequestSchema = pageRequestSchema.extend({
|
|
57
|
+
dueBefore: timestampSchema.optional(),
|
|
58
|
+
endpoint: endpointIdSchema.optional(),
|
|
59
|
+
order: z.enum(SCHEDULE_ORDERS).default("created"),
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* Which end of a history a page walks from.
|
|
63
|
+
*
|
|
64
|
+
* `oldest` is the order every listing has always had and keeps by default; a
|
|
65
|
+
* client that never heard of this parameter sees nothing change. `newest` is
|
|
66
|
+
* what a person looking at a schedule wants (FXO-2259): what happened most
|
|
67
|
+
* recently, first — and on a schedule firing every five minutes for thirty
|
|
68
|
+
* days that is eight thousand rows away from the other end.
|
|
69
|
+
*/
|
|
70
|
+
export const HISTORY_ORDERS = ["oldest", "newest"];
|
|
71
|
+
/** A page request over a history, which may be walked from either end. */
|
|
72
|
+
export const historyPageRequestSchema = pageRequestSchema.extend({
|
|
73
|
+
order: z.enum(HISTORY_ORDERS).default("oldest"),
|
|
74
|
+
});
|
|
26
75
|
/**
|
|
27
76
|
* A page of results.
|
|
28
77
|
*
|
|
@@ -63,6 +112,12 @@ export function pageSchema(item) {
|
|
|
63
112
|
nextCursor: z.string().min(1).optional(),
|
|
64
113
|
});
|
|
65
114
|
}
|
|
115
|
+
function normalizedCursorBinding(binding) {
|
|
116
|
+
return JSON.stringify({
|
|
117
|
+
operation: binding.operation,
|
|
118
|
+
parameters: Object.entries(binding.parameters ?? {}).sort(([left], [right]) => left.localeCompare(right)),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
66
121
|
/**
|
|
67
122
|
* A 32-bit FNV-1a hash of the authority tuple, hex encoded.
|
|
68
123
|
*
|
|
@@ -136,11 +191,13 @@ function base64UrlDecode(value) {
|
|
|
136
191
|
* carries authority, and it carries none — every listing is scoped by the
|
|
137
192
|
* principal before a cursor is even looked at.
|
|
138
193
|
*/
|
|
139
|
-
export function encodeCursor(authority, position) {
|
|
194
|
+
export function encodeCursor(authority, position, binding) {
|
|
140
195
|
return base64UrlEncode(JSON.stringify({
|
|
141
196
|
a: position.createdAtMs,
|
|
197
|
+
...(binding === undefined ? {} : { b: normalizedCursorBinding(binding) }),
|
|
142
198
|
i: position.id,
|
|
143
199
|
k: authorityFingerprint(authority),
|
|
200
|
+
...(position.order === undefined ? {} : { o: position.order }),
|
|
144
201
|
}));
|
|
145
202
|
}
|
|
146
203
|
/**
|
|
@@ -152,7 +209,7 @@ export function encodeCursor(authority, position) {
|
|
|
152
209
|
* their cursor is wrong tells them what a valid one looks like, and the caller
|
|
153
210
|
* never constructs one anyway.
|
|
154
211
|
*/
|
|
155
|
-
export function decodeCursor(authority, cursor) {
|
|
212
|
+
export function decodeCursor(authority, cursor, binding) {
|
|
156
213
|
const decoded = base64UrlDecode(cursor);
|
|
157
214
|
if (decoded === undefined) {
|
|
158
215
|
return undefined;
|
|
@@ -167,47 +224,40 @@ export function decodeCursor(authority, cursor) {
|
|
|
167
224
|
const shape = z
|
|
168
225
|
.object({
|
|
169
226
|
a: z.number().int().nonnegative(),
|
|
227
|
+
b: z.string().min(1).optional(),
|
|
170
228
|
i: z.string().min(1),
|
|
171
229
|
k: z.string(),
|
|
230
|
+
o: z.enum(["created", "due", "newest", "oldest"]).optional(),
|
|
172
231
|
})
|
|
173
232
|
.safeParse(parsed);
|
|
174
|
-
|
|
233
|
+
const expectedBinding = binding === undefined ? undefined : normalizedCursorBinding(binding);
|
|
234
|
+
if (!shape.success ||
|
|
235
|
+
shape.data.k !== authorityFingerprint(authority) ||
|
|
236
|
+
shape.data.b !== expectedBinding) {
|
|
175
237
|
return undefined;
|
|
176
238
|
}
|
|
177
|
-
return {
|
|
239
|
+
return {
|
|
240
|
+
createdAtMs: shape.data.a,
|
|
241
|
+
id: shape.data.i,
|
|
242
|
+
...(shape.data.o === undefined ? {} : { order: shape.data.o }),
|
|
243
|
+
};
|
|
178
244
|
}
|
|
179
245
|
/** Query values arrive as strings; only a whole number may become one. */
|
|
180
246
|
function asNumberIfInteger(value) {
|
|
181
247
|
return /^-?\d+$/u.test(value) ? Number(value) : value;
|
|
182
248
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
* number, and a cursor is opaque precisely so its encoding can change.
|
|
196
|
-
*
|
|
197
|
-
* **Only numeric coercion is derived.** A future page parameter that is neither
|
|
198
|
-
* a string nor a number — a boolean, say — would arrive here as the text
|
|
199
|
-
* `"true"` and be refused by its own schema. That is the safe direction and it
|
|
200
|
-
* is still a trap, so whoever adds one adds its coercion beside this list.
|
|
201
|
-
*
|
|
202
|
-
* Computed once: `toJSONSchema` is not cheap enough to run per request.
|
|
203
|
-
*/
|
|
204
|
-
const PAGE_PARAMETERS = Object.entries(z.toJSONSchema(pageRequestSchema, {
|
|
205
|
-
io: "input",
|
|
206
|
-
unrepresentable: "any",
|
|
207
|
-
}).properties ?? {}).map(([name, schema]) => [
|
|
208
|
-
name,
|
|
209
|
-
schema.type === "integer" || schema.type === "number",
|
|
210
|
-
]);
|
|
249
|
+
const PARAMETERS = new Map();
|
|
250
|
+
function parametersOf(schema) {
|
|
251
|
+
const cached = PARAMETERS.get(schema);
|
|
252
|
+
if (cached !== undefined)
|
|
253
|
+
return cached;
|
|
254
|
+
const derived = Object.entries(z.toJSONSchema(schema, {
|
|
255
|
+
io: "input",
|
|
256
|
+
unrepresentable: "any",
|
|
257
|
+
}).properties ?? {}).map(([name, field]) => [name, field.type === "integer" || field.type === "number"]);
|
|
258
|
+
PARAMETERS.set(schema, derived);
|
|
259
|
+
return derived;
|
|
260
|
+
}
|
|
211
261
|
/**
|
|
212
262
|
* A page request, read from a URL's query string.
|
|
213
263
|
*
|
|
@@ -224,9 +274,20 @@ const PAGE_PARAMETERS = Object.entries(z.toJSONSchema(pageRequestSchema, {
|
|
|
224
274
|
* is the direction compatibility has to hold in.
|
|
225
275
|
*/
|
|
226
276
|
export function parsePageRequest(query) {
|
|
277
|
+
return parseListing(query, pageRequestSchema);
|
|
278
|
+
}
|
|
279
|
+
/** A schedules listing request: the page, and the endpoint filter if given. */
|
|
280
|
+
export function parseScheduleListRequest(query) {
|
|
281
|
+
return parseListing(query, scheduleListRequestSchema);
|
|
282
|
+
}
|
|
283
|
+
/** A history page request: the page, and which end it walks from. */
|
|
284
|
+
export function parseHistoryPageRequest(query) {
|
|
285
|
+
return parseListing(query, historyPageRequestSchema);
|
|
286
|
+
}
|
|
287
|
+
function parseListing(query, schema) {
|
|
227
288
|
const errors = [];
|
|
228
289
|
const raw = {};
|
|
229
|
-
for (const [field, numeric] of
|
|
290
|
+
for (const [field, numeric] of parametersOf(schema)) {
|
|
230
291
|
const values = query.getAll(field);
|
|
231
292
|
if (values.length > 1) {
|
|
232
293
|
errors.push({
|
|
@@ -244,7 +305,7 @@ export function parsePageRequest(query) {
|
|
|
244
305
|
if (errors.length > 0) {
|
|
245
306
|
return { errors, ok: false };
|
|
246
307
|
}
|
|
247
|
-
const parsed =
|
|
308
|
+
const parsed = schema.safeParse(raw);
|
|
248
309
|
if (parsed.success) {
|
|
249
310
|
return { ok: true, page: parsed.data };
|
|
250
311
|
}
|
|
@@ -481,6 +542,17 @@ export const requiredIdempotencyRequestHeaderSchema = z.object({
|
|
|
481
542
|
export const conditionalRequestHeaderSchema = z.object({
|
|
482
543
|
[CONCURRENCY_HEADERS.ifMatch]: etagSchema.optional(),
|
|
483
544
|
});
|
|
545
|
+
/**
|
|
546
|
+
* A conditional write that refuses an unversioned request.
|
|
547
|
+
*
|
|
548
|
+
* Project lifecycle changes use this stricter shape because rename, archive,
|
|
549
|
+
* restore and permanent deletion are management actions over one shared row:
|
|
550
|
+
* silently accepting a missing precondition would let a stale General page
|
|
551
|
+
* overwrite a newer decision.
|
|
552
|
+
*/
|
|
553
|
+
export const requiredConditionalRequestHeaderSchema = z.object({
|
|
554
|
+
[CONCURRENCY_HEADERS.ifMatch]: etagSchema,
|
|
555
|
+
});
|
|
484
556
|
/**
|
|
485
557
|
* Required rather than optional, deliberately: an operation that declares this
|
|
486
558
|
* promises the header on every success, and a client that has to test for its
|