@greatwait/contracts 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/authority.d.ts +217 -0
- package/dist/authority.js +261 -0
- package/dist/callback-ownership.d.ts +58 -0
- package/dist/callback-ownership.js +71 -0
- package/dist/callback-safety.d.ts +38 -0
- package/dist/callback-safety.js +403 -0
- package/dist/compatibility.d.ts +82 -0
- package/dist/compatibility.js +115 -0
- package/dist/delivery.d.ts +401 -0
- package/dist/delivery.js +311 -0
- package/dist/endpoints.d.ts +305 -0
- package/dist/endpoints.js +179 -0
- package/dist/events.d.ts +62 -0
- package/dist/events.js +38 -0
- package/dist/first-value-journey.d.ts +305 -0
- package/dist/first-value-journey.js +466 -0
- package/dist/forecast.d.ts +443 -0
- package/dist/forecast.js +729 -0
- package/dist/identifiers.d.ts +109 -0
- package/dist/identifiers.js +131 -0
- package/dist/identity.d.ts +196 -0
- package/dist/identity.js +182 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +27 -0
- package/dist/mcp.d.ts +51 -0
- package/dist/mcp.js +56 -0
- package/dist/oauth.d.ts +796 -0
- package/dist/oauth.js +708 -0
- package/dist/operations.d.ts +3985 -0
- package/dist/operations.js +1837 -0
- package/dist/partition.d.ts +771 -0
- package/dist/partition.js +206 -0
- package/dist/policy.d.ts +93 -0
- package/dist/policy.js +180 -0
- package/dist/problems.d.ts +158 -0
- package/dist/problems.js +104 -0
- package/dist/protocol.d.ts +308 -0
- package/dist/protocol.js +515 -0
- package/dist/scheduling-records.d.ts +395 -0
- package/dist/scheduling-records.js +284 -0
- package/dist/scheduling.d.ts +1098 -0
- package/dist/scheduling.js +1116 -0
- package/dist/secrets.d.ts +383 -0
- package/dist/secrets.js +272 -0
- package/dist/signatures.d.ts +704 -0
- package/dist/signatures.js +867 -0
- package/dist/tenancy.d.ts +178 -0
- package/dist/tenancy.js +145 -0
- package/dist/test-sink.d.ts +986 -0
- package/dist/test-sink.js +755 -0
- package/dist/time.d.ts +45 -0
- package/dist/time.js +128 -0
- package/dist/usage.d.ts +121 -0
- package/dist/usage.js +200 -0
- package/dist/webhooks.d.ts +116 -0
- package/dist/webhooks.js +161 -0
- package/dist/workspace.d.ts +92 -0
- package/dist/workspace.js +59 -0
- package/generated/v1/callback-delivery-signature.json +467 -0
- package/generated/v1/callback-endpoint-verification.json +59 -0
- package/generated/v1/callback-receiver.json +241 -0
- package/generated/v1/examples/attempts.list.response.json +24 -0
- package/generated/v1/examples/attempts.read.response.json +20 -0
- package/generated/v1/examples/credentials.create.request.json +5 -0
- package/generated/v1/examples/credentials.create.response.json +10 -0
- package/generated/v1/examples/credentials.list.response.json +17 -0
- package/generated/v1/examples/credentials.revoke.response.json +11 -0
- package/generated/v1/examples/credentials.rotate.request.json +3 -0
- package/generated/v1/examples/credentials.rotate.response.json +22 -0
- package/generated/v1/examples/endpoints.create.request.json +3 -0
- package/generated/v1/examples/endpoints.create.response.json +16 -0
- package/generated/v1/examples/endpoints.disable.response.json +15 -0
- package/generated/v1/examples/endpoints.list.response.json +21 -0
- package/generated/v1/examples/endpoints.read.response.json +14 -0
- package/generated/v1/examples/endpoints.rotateSigningKey.request.json +3 -0
- package/generated/v1/examples/endpoints.rotateSigningKey.response.json +23 -0
- package/generated/v1/examples/endpoints.update.request.json +3 -0
- package/generated/v1/examples/endpoints.update.response.json +13 -0
- package/generated/v1/examples/endpoints.verify.response.json +15 -0
- package/generated/v1/examples/forecast.read.response.json +28 -0
- package/generated/v1/examples/forecast.windows.response.json +21 -0
- package/generated/v1/examples/grants.list.response.json +17 -0
- package/generated/v1/examples/grants.revoke.response.json +16 -0
- package/generated/v1/examples/meta.scaffold.response.json +5 -0
- package/generated/v1/examples/meta.version.response.json +5 -0
- package/generated/v1/examples/occurrences.list.response.json +17 -0
- package/generated/v1/examples/occurrences.read.response.json +15 -0
- package/generated/v1/examples/occurrences.redeliver.response.json +16 -0
- package/generated/v1/examples/projects.create.request.json +3 -0
- package/generated/v1/examples/projects.create.response.json +5 -0
- package/generated/v1/examples/projects.list.response.json +9 -0
- package/generated/v1/examples/schedules.archive.response.json +25 -0
- package/generated/v1/examples/schedules.cancel.response.json +24 -0
- package/generated/v1/examples/schedules.create.request.json +9 -0
- package/generated/v1/examples/schedules.create.response.json +25 -0
- package/generated/v1/examples/schedules.list.response.json +23 -0
- package/generated/v1/examples/schedules.pause.response.json +23 -0
- package/generated/v1/examples/schedules.read.response.json +25 -0
- package/generated/v1/examples/schedules.replace.request.json +8 -0
- package/generated/v1/examples/schedules.replace.response.json +25 -0
- package/generated/v1/examples/schedules.resume.response.json +23 -0
- package/generated/v1/examples/sinkdeliveries.list.response.json +19 -0
- package/generated/v1/examples/sinkdeliveries.read.response.json +16 -0
- package/generated/v1/examples/testsinks.configure.request.json +3 -0
- package/generated/v1/examples/testsinks.configure.response.json +13 -0
- package/generated/v1/examples/testsinks.create.request.json +8 -0
- package/generated/v1/examples/testsinks.create.response.json +13 -0
- package/generated/v1/examples/testsinks.delete.response.json +13 -0
- package/generated/v1/examples/testsinks.list.response.json +20 -0
- package/generated/v1/examples/testsinks.read.response.json +14 -0
- package/generated/v1/examples/usage.read.response.json +20 -0
- package/generated/v1/first-value-journey.json +436 -0
- package/generated/v1/manifest.json +1037 -0
- package/generated/v1/openapi.json +23665 -0
- package/generated/v1/policy-matrix.json +305 -0
- package/generated/v1/schemas/attempts.list.query.json +16 -0
- package/generated/v1/schemas/attempts.list.response.json +175 -0
- package/generated/v1/schemas/attempts.read.response.json +168 -0
- package/generated/v1/schemas/credentials.create.request.json +39 -0
- package/generated/v1/schemas/credentials.create.response.json +88 -0
- package/generated/v1/schemas/credentials.list.query.json +16 -0
- package/generated/v1/schemas/credentials.list.response.json +124 -0
- package/generated/v1/schemas/credentials.revoke.response.json +84 -0
- package/generated/v1/schemas/credentials.rotate.request.json +11 -0
- package/generated/v1/schemas/credentials.rotate.response.json +171 -0
- package/generated/v1/schemas/endpoints.create.request.json +12 -0
- package/generated/v1/schemas/endpoints.create.response.json +115 -0
- package/generated/v1/schemas/endpoints.disable.response-headers.json +11 -0
- package/generated/v1/schemas/endpoints.disable.response.json +100 -0
- package/generated/v1/schemas/endpoints.list.query.json +16 -0
- package/generated/v1/schemas/endpoints.list.response.json +146 -0
- package/generated/v1/schemas/endpoints.read.response-headers.json +11 -0
- package/generated/v1/schemas/endpoints.read.response.json +100 -0
- package/generated/v1/schemas/endpoints.rotateSigningKey.request-headers.json +10 -0
- package/generated/v1/schemas/endpoints.rotateSigningKey.request.json +11 -0
- package/generated/v1/schemas/endpoints.rotateSigningKey.response-headers.json +11 -0
- package/generated/v1/schemas/endpoints.rotateSigningKey.response.json +118 -0
- package/generated/v1/schemas/endpoints.update.request-headers.json +10 -0
- package/generated/v1/schemas/endpoints.update.request.json +12 -0
- package/generated/v1/schemas/endpoints.update.response-headers.json +11 -0
- package/generated/v1/schemas/endpoints.update.response.json +100 -0
- package/generated/v1/schemas/endpoints.verify.request-headers.json +10 -0
- package/generated/v1/schemas/endpoints.verify.response-headers.json +11 -0
- package/generated/v1/schemas/endpoints.verify.response.json +100 -0
- package/generated/v1/schemas/forecast.read.query.json +26 -0
- package/generated/v1/schemas/forecast.read.response.json +100 -0
- package/generated/v1/schemas/forecast.windows.query.json +26 -0
- package/generated/v1/schemas/forecast.windows.response.json +94 -0
- package/generated/v1/schemas/grants.list.response.json +98 -0
- package/generated/v1/schemas/grants.revoke.response.json +95 -0
- package/generated/v1/schemas/meta.scaffold.response.json +36 -0
- package/generated/v1/schemas/meta.version.response.json +19 -0
- package/generated/v1/schemas/occurrences.list.query.json +16 -0
- package/generated/v1/schemas/occurrences.list.response.json +83 -0
- package/generated/v1/schemas/occurrences.read.response.json +76 -0
- package/generated/v1/schemas/occurrences.redeliver.request-headers.json +13 -0
- package/generated/v1/schemas/occurrences.redeliver.response-headers.json +10 -0
- package/generated/v1/schemas/occurrences.redeliver.response.json +168 -0
- package/generated/v1/schemas/projects.create.request.json +12 -0
- package/generated/v1/schemas/projects.create.response.json +25 -0
- package/generated/v1/schemas/projects.list.response.json +35 -0
- package/generated/v1/schemas/schedules.archive.request-headers.json +10 -0
- package/generated/v1/schemas/schedules.archive.response-headers.json +11 -0
- package/generated/v1/schemas/schedules.archive.response.json +189 -0
- package/generated/v1/schemas/schedules.cancel.request-headers.json +10 -0
- package/generated/v1/schemas/schedules.cancel.response-headers.json +11 -0
- package/generated/v1/schemas/schedules.cancel.response.json +189 -0
- package/generated/v1/schemas/schedules.create.request-headers.json +12 -0
- package/generated/v1/schemas/schedules.create.request.json +99 -0
- package/generated/v1/schemas/schedules.create.response-headers.json +15 -0
- package/generated/v1/schemas/schedules.create.response.json +189 -0
- package/generated/v1/schemas/schedules.list.query.json +16 -0
- package/generated/v1/schemas/schedules.list.response.json +170 -0
- package/generated/v1/schemas/schedules.pause.request-headers.json +10 -0
- package/generated/v1/schemas/schedules.pause.response-headers.json +11 -0
- package/generated/v1/schemas/schedules.pause.response.json +189 -0
- package/generated/v1/schemas/schedules.read.response-headers.json +11 -0
- package/generated/v1/schemas/schedules.read.response.json +189 -0
- package/generated/v1/schemas/schedules.replace.request-headers.json +10 -0
- package/generated/v1/schemas/schedules.replace.request.json +99 -0
- package/generated/v1/schemas/schedules.replace.response-headers.json +11 -0
- package/generated/v1/schemas/schedules.replace.response.json +189 -0
- package/generated/v1/schemas/schedules.resume.request-headers.json +10 -0
- package/generated/v1/schemas/schedules.resume.response-headers.json +11 -0
- package/generated/v1/schemas/schedules.resume.response.json +189 -0
- package/generated/v1/schemas/sinkdeliveries.list.query.json +16 -0
- package/generated/v1/schemas/sinkdeliveries.list.response.json +126 -0
- package/generated/v1/schemas/sinkdeliveries.read.response.json +98 -0
- package/generated/v1/schemas/testsinks.configure.request.json +66 -0
- package/generated/v1/schemas/testsinks.configure.response.json +115 -0
- package/generated/v1/schemas/testsinks.create.request.json +76 -0
- package/generated/v1/schemas/testsinks.create.response.json +115 -0
- package/generated/v1/schemas/testsinks.delete.response.json +115 -0
- package/generated/v1/schemas/testsinks.list.query.json +16 -0
- package/generated/v1/schemas/testsinks.list.response.json +161 -0
- package/generated/v1/schemas/testsinks.read.response.json +115 -0
- package/generated/v1/schemas/usage.read.query.json +15 -0
- package/generated/v1/schemas/usage.read.response.json +71 -0
- package/generated/v1/snippets/attempts.list.json +5 -0
- package/generated/v1/snippets/attempts.read.json +5 -0
- package/generated/v1/snippets/credentials.create.json +5 -0
- package/generated/v1/snippets/credentials.list.json +5 -0
- package/generated/v1/snippets/credentials.revoke.json +5 -0
- package/generated/v1/snippets/credentials.rotate.json +5 -0
- package/generated/v1/snippets/endpoints.create.json +5 -0
- package/generated/v1/snippets/endpoints.disable.json +5 -0
- package/generated/v1/snippets/endpoints.list.json +5 -0
- package/generated/v1/snippets/endpoints.read.json +5 -0
- package/generated/v1/snippets/endpoints.rotateSigningKey.json +5 -0
- package/generated/v1/snippets/endpoints.update.json +5 -0
- package/generated/v1/snippets/endpoints.verify.json +5 -0
- package/generated/v1/snippets/forecast.read.json +5 -0
- package/generated/v1/snippets/forecast.windows.json +5 -0
- package/generated/v1/snippets/grants.list.json +5 -0
- package/generated/v1/snippets/grants.revoke.json +5 -0
- package/generated/v1/snippets/meta.scaffold.json +5 -0
- package/generated/v1/snippets/meta.version.json +5 -0
- package/generated/v1/snippets/occurrences.list.json +5 -0
- package/generated/v1/snippets/occurrences.read.json +5 -0
- package/generated/v1/snippets/occurrences.redeliver.json +5 -0
- package/generated/v1/snippets/projects.create.json +5 -0
- package/generated/v1/snippets/projects.list.json +5 -0
- package/generated/v1/snippets/schedules.archive.json +5 -0
- package/generated/v1/snippets/schedules.cancel.json +5 -0
- package/generated/v1/snippets/schedules.create.json +5 -0
- package/generated/v1/snippets/schedules.list.json +5 -0
- package/generated/v1/snippets/schedules.pause.json +5 -0
- package/generated/v1/snippets/schedules.read.json +5 -0
- package/generated/v1/snippets/schedules.replace.json +5 -0
- package/generated/v1/snippets/schedules.resume.json +5 -0
- package/generated/v1/snippets/sinkdeliveries.list.json +5 -0
- package/generated/v1/snippets/sinkdeliveries.read.json +5 -0
- package/generated/v1/snippets/testsinks.configure.json +5 -0
- package/generated/v1/snippets/testsinks.create.json +5 -0
- package/generated/v1/snippets/testsinks.delete.json +5 -0
- package/generated/v1/snippets/testsinks.list.json +5 -0
- package/generated/v1/snippets/testsinks.read.json +5 -0
- package/generated/v1/snippets/usage.read.json +5 -0
- package/package.json +153 -0
package/dist/delivery.js
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Versioned associated-data contract for encrypted schedule payloads.
|
|
3
|
+
*
|
|
4
|
+
* The value is persisted beside the envelope by the portable scheduling
|
|
5
|
+
* record contract. Changing it requires an explicit reader for the old value;
|
|
6
|
+
* silently trying another value would turn an authentication failure into a
|
|
7
|
+
* decryption oracle.
|
|
8
|
+
*/
|
|
9
|
+
export const SCHEDULE_PAYLOAD_AAD_VERSION = "greatwait.schedule-payload.v1";
|
|
10
|
+
/**
|
|
11
|
+
* What a receiver says about work it acknowledged and then finished.
|
|
12
|
+
*
|
|
13
|
+
* Here rather than beside the envelope schema because the scheduler Worker's
|
|
14
|
+
* completion route reads it and that bundle deliberately carries no Zod — this
|
|
15
|
+
* module is the Zod-free subpath. `signatures.ts` builds its enum from this
|
|
16
|
+
* list, so the vocabulary exists once.
|
|
17
|
+
*
|
|
18
|
+
* `succeeded` is what an empty body means: the overwhelmingly common report is
|
|
19
|
+
* "done", and a receiver should not have to compose a document to say it.
|
|
20
|
+
* `failed` puts the occurrence back on the ordinary retry ladder — the same
|
|
21
|
+
* place a 500 puts it — so a receiver can distinguish "my job died" from "I
|
|
22
|
+
* vanished".
|
|
23
|
+
*/
|
|
24
|
+
export const CALLBACK_COMPLETION_OUTCOMES = ["succeeded", "failed"];
|
|
25
|
+
/**
|
|
26
|
+
* The one status that can mean "I have the work and I am not finished".
|
|
27
|
+
*
|
|
28
|
+
* Exactly `202`, and the narrowness is the point. Every other 2xx keeps the
|
|
29
|
+
* meaning it has had since the first delivery this product sent — success,
|
|
30
|
+
* now — so a receiver that has never heard of deferral cannot be parked by
|
|
31
|
+
* accident. A `200` carrying the marker is success, and so is a `204`, because
|
|
32
|
+
* the discriminator is not the whole rule: the status and the body have to
|
|
33
|
+
* agree, and only this pair opts in.
|
|
34
|
+
*/
|
|
35
|
+
export const CALLBACK_DEFERRAL_STATUS = 202;
|
|
36
|
+
/**
|
|
37
|
+
* How much of an acknowledgement body is read before the answer is decided.
|
|
38
|
+
*
|
|
39
|
+
* One kibibyte. An acknowledgement is a fixed object of two or three short
|
|
40
|
+
* members, so the bound is roughly twenty times what a legitimate one needs
|
|
41
|
+
* and is not a limit a receiver can meet by accident. What it stops is a
|
|
42
|
+
* receiver — or something in front of one — answering `202` with a body that
|
|
43
|
+
* is expensive to read: the delivery path reads this many bytes, decides, and
|
|
44
|
+
* cancels the rest of the stream without buffering it.
|
|
45
|
+
*
|
|
46
|
+
* **Exceeding it is not pending.** A body over the bound cannot be shown to
|
|
47
|
+
* carry the discriminator, and the safe reading of "cannot be shown" is the
|
|
48
|
+
* one that settles the attempt now rather than the one that parks a customer's
|
|
49
|
+
* occurrence on a receiver whose answer we did not finish reading.
|
|
50
|
+
*/
|
|
51
|
+
export const CALLBACK_ACKNOWLEDGEMENT_MAX_BYTES = 1_024;
|
|
52
|
+
/**
|
|
53
|
+
* The media types an acknowledgement may be carried in.
|
|
54
|
+
*
|
|
55
|
+
* JSON, in the two spellings a receiver actually sends. A `202` whose body is
|
|
56
|
+
* HTML or plain text is an ordinary success, because whatever it says it is
|
|
57
|
+
* not this protocol.
|
|
58
|
+
*/
|
|
59
|
+
export const CALLBACK_ACKNOWLEDGEMENT_CONTENT_TYPES = [
|
|
60
|
+
"application/json",
|
|
61
|
+
"application/problem+json",
|
|
62
|
+
];
|
|
63
|
+
/**
|
|
64
|
+
* What a receiver answers with to keep the work and report later.
|
|
65
|
+
*
|
|
66
|
+
* ```json
|
|
67
|
+
* { "greatwait": { "status": "pending", "completeBy": "2026-08-23T18:00:00Z" } }
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* **Namespaced under one key on purpose.** A receiver's `202` body is its own
|
|
71
|
+
* document — a job id, a queue position, a status URL — and a bare
|
|
72
|
+
* `{"status":"pending"}` would collide with the most ordinary word in that
|
|
73
|
+
* vocabulary. Nesting it means an existing receiver has to have chosen the key
|
|
74
|
+
* `greatwait` for something else before this can misfire.
|
|
75
|
+
*/
|
|
76
|
+
export const CALLBACK_PENDING_DISCRIMINATOR = {
|
|
77
|
+
key: "greatwait",
|
|
78
|
+
status: "pending",
|
|
79
|
+
};
|
|
80
|
+
const NOT_PENDING = { pending: false };
|
|
81
|
+
/**
|
|
82
|
+
* RFC 3339 with an explicit offset, fractional seconds optional.
|
|
83
|
+
*
|
|
84
|
+
* **Deliberately wider than `timestampSchema` and deliberately narrower than
|
|
85
|
+
* `Date.parse`.** This value crosses in from a receiver rather than out from
|
|
86
|
+
* this service, so demanding the product's own millisecond-and-`Z` spelling
|
|
87
|
+
* would silently discard a correct instant written the ordinary way. What is
|
|
88
|
+
* still refused is anything whose meaning depends on where it is read: a bare
|
|
89
|
+
* date, a local wall clock with no offset, an epoch number, and every other
|
|
90
|
+
* shape `Date.parse` is willing to guess at.
|
|
91
|
+
*/
|
|
92
|
+
const RFC3339_INSTANT = /^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[Zz]|[+-]\d{2}:\d{2})$/u;
|
|
93
|
+
function readCompleteBy(value) {
|
|
94
|
+
if (typeof value !== "string" || !RFC3339_INSTANT.test(value)) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
const parsed = Date.parse(value);
|
|
98
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
99
|
+
}
|
|
100
|
+
function isAcknowledgementContentType(value) {
|
|
101
|
+
if (value === null)
|
|
102
|
+
return false;
|
|
103
|
+
// Parameters are the receiver's business; `application/json; charset=utf-8`
|
|
104
|
+
// is the same media type as `application/json`.
|
|
105
|
+
const media = value.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
106
|
+
return CALLBACK_ACKNOWLEDGEMENT_CONTENT_TYPES.includes(media);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Decide whether one receiver answer is the deferral acknowledgement.
|
|
110
|
+
*
|
|
111
|
+
* Every term is required and each one is refused on its own: the status is
|
|
112
|
+
* exactly {@link CALLBACK_DEFERRAL_STATUS}, the media type is JSON, the body
|
|
113
|
+
* fits {@link CALLBACK_ACKNOWLEDGEMENT_MAX_BYTES}, it parses, it is a JSON
|
|
114
|
+
* object rather than an array or a scalar, and it carries the discriminator.
|
|
115
|
+
* Anything that fails one of them is not pending, which for a 2xx means
|
|
116
|
+
* ordinary immediate success.
|
|
117
|
+
*
|
|
118
|
+
* **It never decides a non-2xx.** The caller classifies the response first and
|
|
119
|
+
* only asks this about a success; a `500` carrying a perfectly formed pending
|
|
120
|
+
* marker is a `500`, because a receiver that is failing does not get to park
|
|
121
|
+
* the occurrence it is failing to handle.
|
|
122
|
+
*
|
|
123
|
+
* **There is no `Array.isArray` guard, and there was one.** Mutation testing
|
|
124
|
+
* showed both — over the parsed body and over the marker — surviving deletion
|
|
125
|
+
* with every case green, and the reason is that they cannot decide anything: a
|
|
126
|
+
* JSON array has no named members, so reading the discriminator key off one is
|
|
127
|
+
* `undefined` and the very next check refuses it. A rule no input can reach
|
|
128
|
+
* reads like protection and is not, so it is gone and this paragraph is what
|
|
129
|
+
* it left behind. The array cases in the suite stay — they pin the outcome a
|
|
130
|
+
* receiver sees, which is unchanged — but they hold by construction rather
|
|
131
|
+
* than by a guard.
|
|
132
|
+
*/
|
|
133
|
+
export function readCallbackAcknowledgement(response) {
|
|
134
|
+
if (response.status !== CALLBACK_DEFERRAL_STATUS)
|
|
135
|
+
return NOT_PENDING;
|
|
136
|
+
if (response.truncated)
|
|
137
|
+
return NOT_PENDING;
|
|
138
|
+
if (!isAcknowledgementContentType(response.contentType))
|
|
139
|
+
return NOT_PENDING;
|
|
140
|
+
let parsed;
|
|
141
|
+
try {
|
|
142
|
+
parsed = JSON.parse(response.body);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return NOT_PENDING;
|
|
146
|
+
}
|
|
147
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
148
|
+
return NOT_PENDING;
|
|
149
|
+
const marker = parsed[CALLBACK_PENDING_DISCRIMINATOR.key];
|
|
150
|
+
if (typeof marker !== "object" || marker === null)
|
|
151
|
+
return NOT_PENDING;
|
|
152
|
+
const fields = marker;
|
|
153
|
+
if (fields["status"] !== CALLBACK_PENDING_DISCRIMINATOR.status) {
|
|
154
|
+
return NOT_PENDING;
|
|
155
|
+
}
|
|
156
|
+
const completeByMs = readCompleteBy(fields["completeBy"]);
|
|
157
|
+
return completeByMs === undefined
|
|
158
|
+
? { pending: true }
|
|
159
|
+
: { completeByMs, pending: true };
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* The deadline this deferral actually gets, in epoch milliseconds.
|
|
163
|
+
*
|
|
164
|
+
* The receiver may bring it forward and may not push it out. `maximumMs` is
|
|
165
|
+
* the deadline already inside the signed envelope — the schedule's own
|
|
166
|
+
* duration allowance measured from the attempt — so a receiver asking for
|
|
167
|
+
* longer is asking to change what its customer bought, and a receiver asking
|
|
168
|
+
* for an instant that has already passed is asking for something no wait can
|
|
169
|
+
* satisfy.
|
|
170
|
+
*
|
|
171
|
+
* **All three refusals fall back to the maximum rather than to immediate
|
|
172
|
+
* success.** The acknowledgement itself is what took the work; a malformed
|
|
173
|
+
* hint about *when* does not unmake that, and settling such an attempt
|
|
174
|
+
* `succeeded` would record a result the receiver never reported.
|
|
175
|
+
*/
|
|
176
|
+
export function effectiveCompletionDeadlineMs(requestedMs, maximumMs, nowMs) {
|
|
177
|
+
if (requestedMs === undefined || !Number.isFinite(requestedMs)) {
|
|
178
|
+
return maximumMs;
|
|
179
|
+
}
|
|
180
|
+
if (requestedMs <= nowMs)
|
|
181
|
+
return maximumMs;
|
|
182
|
+
return Math.min(requestedMs, maximumMs);
|
|
183
|
+
}
|
|
184
|
+
/** Safe, bounded diagnostics. Never contains a URL, payload, or secret. */
|
|
185
|
+
/**
|
|
186
|
+
* Safe delivery diagnostics shared by the executor result and the public
|
|
187
|
+
* attempt timeline.
|
|
188
|
+
*
|
|
189
|
+
* Values are deliberately short categories. A URL, response body, payload,
|
|
190
|
+
* exception message, signing key, or transport trace has no representation in
|
|
191
|
+
* this vocabulary, so the durable history cannot accidentally turn private
|
|
192
|
+
* callback material into a public diagnostic.
|
|
193
|
+
*/
|
|
194
|
+
export const CALLBACK_ATTEMPT_DIAGNOSTICS = [
|
|
195
|
+
"completion_timed_out",
|
|
196
|
+
"delivered",
|
|
197
|
+
"duplicate_inflight",
|
|
198
|
+
"endpoint_unavailable",
|
|
199
|
+
"endpoint_unsafe",
|
|
200
|
+
"http_refused",
|
|
201
|
+
"http_retryable",
|
|
202
|
+
"http_terminal",
|
|
203
|
+
"identity_conflict",
|
|
204
|
+
"network_ambiguous",
|
|
205
|
+
"payload_unavailable",
|
|
206
|
+
"rate_limited",
|
|
207
|
+
];
|
|
208
|
+
/**
|
|
209
|
+
* Statuses where the receiver is refusing *this delivery, right now* rather
|
|
210
|
+
* than objecting to the message it carries.
|
|
211
|
+
*
|
|
212
|
+
* **The line is whether resending the identical bytes could ever get a
|
|
213
|
+
* different answer.** Every callback attempt re-sends the same signed envelope,
|
|
214
|
+
* so a receiver that rejects the message itself — malformed, too large, wrong
|
|
215
|
+
* media type, gone, refused for legal reasons — will reject it identically for
|
|
216
|
+
* as long as the occurrence lives, and retrying is pure cost on the population
|
|
217
|
+
* least likely to recover. A receiver that refuses *us* has a cause someone
|
|
218
|
+
* fixes: an expired or rotated credential, a WAF rule that started matching, a
|
|
219
|
+
* deploy window where the route is briefly absent.
|
|
220
|
+
*
|
|
221
|
+
* | Status | Why it is here |
|
|
222
|
+
* | ------ | -------------- |
|
|
223
|
+
* | 401 | credential expired, rotated, or not yet deployed |
|
|
224
|
+
* | 402 | receiver's own service suspended, restored on payment |
|
|
225
|
+
* | 403 | WAF or bot rule, revoked permission, IP block |
|
|
226
|
+
* | 404 | route absent during a deploy or a partial rollout |
|
|
227
|
+
* | 405 | method absent during a deploy or a partial rollout |
|
|
228
|
+
* | 407 | an egress proxy in front of the receiver wants credentials |
|
|
229
|
+
* | 421 | misdirected during a routing or certificate change |
|
|
230
|
+
* | 423 | the target resource is temporarily locked |
|
|
231
|
+
* | 424 | the receiver's own dependency failed |
|
|
232
|
+
* | 425 | the receiver asked us not to risk a replay yet — literally "retry later" |
|
|
233
|
+
*
|
|
234
|
+
* **409 is deliberately not here**, though it is a refusal in the plain
|
|
235
|
+
* reading. From a callback receiver a conflict overwhelmingly means "I already
|
|
236
|
+
* have this delivery", which the identical retry cannot resolve and which is
|
|
237
|
+
* the receiver's idempotency working rather than failing.
|
|
238
|
+
*
|
|
239
|
+
* **An unrecognised 4xx is not here either.** RFC 7231 says an unknown 4xx must
|
|
240
|
+
* be treated as a 400, so the default is terminal and this list is the whole of
|
|
241
|
+
* the exception. Adding to it is a product decision, not a lookup.
|
|
242
|
+
*/
|
|
243
|
+
export const CALLBACK_REFUSAL_STATUSES = [
|
|
244
|
+
401, 402, 403, 404, 405, 407, 421, 423, 424, 425,
|
|
245
|
+
];
|
|
246
|
+
/** Whether a receiver refused this delivery in a way that may recover. */
|
|
247
|
+
export function isCallbackRefusalStatus(status) {
|
|
248
|
+
return CALLBACK_REFUSAL_STATUSES.includes(status);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Response headers worth keeping, in the order one is chosen.
|
|
252
|
+
*
|
|
253
|
+
* **A closed list, and short on purpose.** A response header is receiver-
|
|
254
|
+
* controlled text that lands in durable history and on a support screen, so
|
|
255
|
+
* the question is not "is this one dangerous" but "does this one earn its
|
|
256
|
+
* place". Content type explains what the snippet is, `Retry-After` explains a
|
|
257
|
+
* pacing decision the customer can see, and one receiver-side identifier is
|
|
258
|
+
* what turns "your receiver refused this" into something an integrator can
|
|
259
|
+
* look up in their own logs.
|
|
260
|
+
*
|
|
261
|
+
* Everything else is absent by construction rather than by filtering: cookies,
|
|
262
|
+
* `Authorization`, `WWW-Authenticate`, `Set-Cookie` and every vendor header
|
|
263
|
+
* have no entry here, so no future edit can retain one by forgetting to add a
|
|
264
|
+
* denial.
|
|
265
|
+
*/
|
|
266
|
+
export const CALLBACK_RESPONSE_HEADER_ALLOWLIST = [
|
|
267
|
+
"content-type",
|
|
268
|
+
"retry-after",
|
|
269
|
+
];
|
|
270
|
+
/**
|
|
271
|
+
* Receiver-side identifiers, most specific first. **At most one is kept.**
|
|
272
|
+
*
|
|
273
|
+
* The order is which name a receiver most likely means as "look this up in my
|
|
274
|
+
* logs". Keeping several would be keeping a header set rather than an
|
|
275
|
+
* identifier, which is the thing the allowlist above exists to refuse.
|
|
276
|
+
*/
|
|
277
|
+
export const CALLBACK_RESPONSE_REQUEST_ID_HEADERS = [
|
|
278
|
+
"x-request-id",
|
|
279
|
+
"request-id",
|
|
280
|
+
"x-correlation-id",
|
|
281
|
+
"x-amzn-requestid",
|
|
282
|
+
"cf-ray",
|
|
283
|
+
];
|
|
284
|
+
/** How much of any retained header value is kept, in bytes. */
|
|
285
|
+
export const CALLBACK_RESPONSE_HEADER_MAX_BYTES = 256;
|
|
286
|
+
/**
|
|
287
|
+
* How much of a failed response body may be retained, in bytes.
|
|
288
|
+
*
|
|
289
|
+
* Four kibibytes of the *start* of the body, read as a bounded prefix and with
|
|
290
|
+
* the rest of the stream cancelled rather than buffered. It is enough for a
|
|
291
|
+
* stack trace's first frames or a validation error list, which is what makes a
|
|
292
|
+
* failing receiver diagnosable without turning this product into a log store.
|
|
293
|
+
*/
|
|
294
|
+
export const CALLBACK_FAILURE_SNIPPET_MAX_BYTES = 4_096;
|
|
295
|
+
/**
|
|
296
|
+
* Media types whose body may be retained as a failure snippet.
|
|
297
|
+
*
|
|
298
|
+
* Text and JSON only. A binary body has nothing a person reads in its first
|
|
299
|
+
* four kibibytes, and retaining one would mean storing an arbitrary fragment
|
|
300
|
+
* of an arbitrary file because a receiver set a header.
|
|
301
|
+
*/
|
|
302
|
+
export const CALLBACK_FAILURE_SNIPPET_CONTENT_TYPES = [
|
|
303
|
+
"application/json",
|
|
304
|
+
"application/problem+json",
|
|
305
|
+
"application/xml",
|
|
306
|
+
"text/",
|
|
307
|
+
];
|
|
308
|
+
/** Whether one network attempt asked to finish later. */
|
|
309
|
+
export function isDeferredAttempt(outcome) {
|
|
310
|
+
return "deferred" in outcome;
|
|
311
|
+
}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Reusable callback endpoints.
|
|
4
|
+
*
|
|
5
|
+
* The URL belongs to one verified authority tuple for its whole life. The
|
|
6
|
+
* public resource deliberately has no organization or environment identifier
|
|
7
|
+
* a caller can use to widen that tuple: `project` and `environmentKind` are
|
|
8
|
+
* display metadata, while every lookup is scoped by the verified principal.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CALLBACK_ENDPOINT_STATUSES: readonly ["pending", "verified", "disabled"];
|
|
11
|
+
export declare const callbackEndpointStatusSchema: z.ZodEnum<{
|
|
12
|
+
verified: "verified";
|
|
13
|
+
pending: "pending";
|
|
14
|
+
disabled: "disabled";
|
|
15
|
+
}>;
|
|
16
|
+
export type CallbackEndpointStatus = z.infer<typeof callbackEndpointStatusSchema>;
|
|
17
|
+
export declare const CALLBACK_VERIFICATION_FAILURES: readonly ["address_forbidden", "challenge_failed", "connection_failed", "dns_unresolved", "rate_limited", "redirect_refused", "response_too_large", "timed_out", "unexpected_status"];
|
|
18
|
+
export declare const callbackVerificationFailureSchema: z.ZodEnum<{
|
|
19
|
+
rate_limited: "rate_limited";
|
|
20
|
+
address_forbidden: "address_forbidden";
|
|
21
|
+
challenge_failed: "challenge_failed";
|
|
22
|
+
connection_failed: "connection_failed";
|
|
23
|
+
dns_unresolved: "dns_unresolved";
|
|
24
|
+
redirect_refused: "redirect_refused";
|
|
25
|
+
response_too_large: "response_too_large";
|
|
26
|
+
timed_out: "timed_out";
|
|
27
|
+
unexpected_status: "unexpected_status";
|
|
28
|
+
}>;
|
|
29
|
+
export type CallbackVerificationFailure = z.infer<typeof callbackVerificationFailureSchema>;
|
|
30
|
+
/**
|
|
31
|
+
* A safety ceiling on retained endpoint records, independent of later
|
|
32
|
+
* commercial plan limits. Disabled records remain readable for audit and count
|
|
33
|
+
* toward it; changing that lifetime semantic needs a product decision.
|
|
34
|
+
*/
|
|
35
|
+
export declare const CALLBACK_ENDPOINT_LIMIT_PER_ENVIRONMENT = 50;
|
|
36
|
+
/** Verification egress is admitted through both buckets before DNS or fetch. */
|
|
37
|
+
export declare const CALLBACK_VERIFICATION_RATE_LIMITS: {
|
|
38
|
+
readonly destinationPerMinute: 5;
|
|
39
|
+
readonly projectPerMinute: 20;
|
|
40
|
+
readonly windowSeconds: 60;
|
|
41
|
+
};
|
|
42
|
+
/** Total bytes a verification response may return before it is refused. */
|
|
43
|
+
export declare const CALLBACK_VERIFICATION_RESPONSE_BYTES = 1024;
|
|
44
|
+
/** Total DNS + connect + response bound for one verification attempt. */
|
|
45
|
+
export declare const CALLBACK_VERIFICATION_TIMEOUT_MILLISECONDS = 5000;
|
|
46
|
+
/** Longest period during which a receiver may accept current and next keys. */
|
|
47
|
+
export declare const CALLBACK_SIGNING_KEY_ROTATION_OVERLAP_SECONDS = 86400;
|
|
48
|
+
export declare const callbackSigningKeysSchema: z.ZodObject<{
|
|
49
|
+
current: z.ZodString;
|
|
50
|
+
next: z.ZodOptional<z.ZodObject<{
|
|
51
|
+
id: z.ZodString;
|
|
52
|
+
overlapEndsAt: z.ZodString;
|
|
53
|
+
}, z.core.$strip>>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
export type CallbackSigningKeys = z.infer<typeof callbackSigningKeysSchema>;
|
|
56
|
+
/**
|
|
57
|
+
* A metadata-only endpoint shape. The sealed signing secret has no public
|
|
58
|
+
* field, so list/get/update/verify/disable cannot accidentally recover it.
|
|
59
|
+
*/
|
|
60
|
+
export declare const callbackEndpointSchema: z.ZodObject<{
|
|
61
|
+
createdAt: z.ZodString;
|
|
62
|
+
disabledAt: z.ZodOptional<z.ZodString>;
|
|
63
|
+
environmentKind: z.ZodEnum<{
|
|
64
|
+
test: "test";
|
|
65
|
+
live: "live";
|
|
66
|
+
}>;
|
|
67
|
+
id: z.ZodString;
|
|
68
|
+
lastVerificationAttemptAt: z.ZodOptional<z.ZodString>;
|
|
69
|
+
lastVerificationFailure: z.ZodOptional<z.ZodEnum<{
|
|
70
|
+
rate_limited: "rate_limited";
|
|
71
|
+
address_forbidden: "address_forbidden";
|
|
72
|
+
challenge_failed: "challenge_failed";
|
|
73
|
+
connection_failed: "connection_failed";
|
|
74
|
+
dns_unresolved: "dns_unresolved";
|
|
75
|
+
redirect_refused: "redirect_refused";
|
|
76
|
+
response_too_large: "response_too_large";
|
|
77
|
+
timed_out: "timed_out";
|
|
78
|
+
unexpected_status: "unexpected_status";
|
|
79
|
+
}>>;
|
|
80
|
+
project: z.ZodString;
|
|
81
|
+
signingKeys: z.ZodObject<{
|
|
82
|
+
current: z.ZodString;
|
|
83
|
+
next: z.ZodOptional<z.ZodObject<{
|
|
84
|
+
id: z.ZodString;
|
|
85
|
+
overlapEndsAt: z.ZodString;
|
|
86
|
+
}, z.core.$strip>>;
|
|
87
|
+
}, z.core.$strip>;
|
|
88
|
+
status: z.ZodEnum<{
|
|
89
|
+
verified: "verified";
|
|
90
|
+
pending: "pending";
|
|
91
|
+
disabled: "disabled";
|
|
92
|
+
}>;
|
|
93
|
+
updatedAt: z.ZodString;
|
|
94
|
+
url: z.ZodString;
|
|
95
|
+
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
96
|
+
version: z.ZodNumber;
|
|
97
|
+
}, z.core.$strip>;
|
|
98
|
+
export type CallbackEndpoint = z.infer<typeof callbackEndpointSchema>;
|
|
99
|
+
export declare const callbackEndpointPageSchema: z.ZodObject<{
|
|
100
|
+
data: z.ZodArray<z.ZodObject<{
|
|
101
|
+
createdAt: z.ZodString;
|
|
102
|
+
disabledAt: z.ZodOptional<z.ZodString>;
|
|
103
|
+
environmentKind: z.ZodEnum<{
|
|
104
|
+
test: "test";
|
|
105
|
+
live: "live";
|
|
106
|
+
}>;
|
|
107
|
+
id: z.ZodString;
|
|
108
|
+
lastVerificationAttemptAt: z.ZodOptional<z.ZodString>;
|
|
109
|
+
lastVerificationFailure: z.ZodOptional<z.ZodEnum<{
|
|
110
|
+
rate_limited: "rate_limited";
|
|
111
|
+
address_forbidden: "address_forbidden";
|
|
112
|
+
challenge_failed: "challenge_failed";
|
|
113
|
+
connection_failed: "connection_failed";
|
|
114
|
+
dns_unresolved: "dns_unresolved";
|
|
115
|
+
redirect_refused: "redirect_refused";
|
|
116
|
+
response_too_large: "response_too_large";
|
|
117
|
+
timed_out: "timed_out";
|
|
118
|
+
unexpected_status: "unexpected_status";
|
|
119
|
+
}>>;
|
|
120
|
+
project: z.ZodString;
|
|
121
|
+
signingKeys: z.ZodObject<{
|
|
122
|
+
current: z.ZodString;
|
|
123
|
+
next: z.ZodOptional<z.ZodObject<{
|
|
124
|
+
id: z.ZodString;
|
|
125
|
+
overlapEndsAt: z.ZodString;
|
|
126
|
+
}, z.core.$strip>>;
|
|
127
|
+
}, z.core.$strip>;
|
|
128
|
+
status: z.ZodEnum<{
|
|
129
|
+
verified: "verified";
|
|
130
|
+
pending: "pending";
|
|
131
|
+
disabled: "disabled";
|
|
132
|
+
}>;
|
|
133
|
+
updatedAt: z.ZodString;
|
|
134
|
+
url: z.ZodString;
|
|
135
|
+
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
136
|
+
version: z.ZodNumber;
|
|
137
|
+
}, z.core.$strip>>;
|
|
138
|
+
freshness: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
139
|
+
kind: z.ZodLiteral<"authoritative">;
|
|
140
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
141
|
+
asOf: z.ZodString;
|
|
142
|
+
kind: z.ZodLiteral<"projected">;
|
|
143
|
+
lagSeconds: z.ZodNumber;
|
|
144
|
+
}, z.core.$strip>], "kind">;
|
|
145
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
146
|
+
}, z.core.$strip>;
|
|
147
|
+
export type CallbackEndpointPage = z.infer<typeof callbackEndpointPageSchema>;
|
|
148
|
+
/** The one response that carries the per-endpoint secret. */
|
|
149
|
+
export declare const callbackEndpointCreatedSchema: z.ZodObject<{
|
|
150
|
+
createdAt: z.ZodString;
|
|
151
|
+
disabledAt: z.ZodOptional<z.ZodString>;
|
|
152
|
+
environmentKind: z.ZodEnum<{
|
|
153
|
+
test: "test";
|
|
154
|
+
live: "live";
|
|
155
|
+
}>;
|
|
156
|
+
id: z.ZodString;
|
|
157
|
+
lastVerificationAttemptAt: z.ZodOptional<z.ZodString>;
|
|
158
|
+
lastVerificationFailure: z.ZodOptional<z.ZodEnum<{
|
|
159
|
+
rate_limited: "rate_limited";
|
|
160
|
+
address_forbidden: "address_forbidden";
|
|
161
|
+
challenge_failed: "challenge_failed";
|
|
162
|
+
connection_failed: "connection_failed";
|
|
163
|
+
dns_unresolved: "dns_unresolved";
|
|
164
|
+
redirect_refused: "redirect_refused";
|
|
165
|
+
response_too_large: "response_too_large";
|
|
166
|
+
timed_out: "timed_out";
|
|
167
|
+
unexpected_status: "unexpected_status";
|
|
168
|
+
}>>;
|
|
169
|
+
project: z.ZodString;
|
|
170
|
+
signingKeys: z.ZodObject<{
|
|
171
|
+
current: z.ZodString;
|
|
172
|
+
next: z.ZodOptional<z.ZodObject<{
|
|
173
|
+
id: z.ZodString;
|
|
174
|
+
overlapEndsAt: z.ZodString;
|
|
175
|
+
}, z.core.$strip>>;
|
|
176
|
+
}, z.core.$strip>;
|
|
177
|
+
status: z.ZodEnum<{
|
|
178
|
+
verified: "verified";
|
|
179
|
+
pending: "pending";
|
|
180
|
+
disabled: "disabled";
|
|
181
|
+
}>;
|
|
182
|
+
updatedAt: z.ZodString;
|
|
183
|
+
url: z.ZodString;
|
|
184
|
+
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
185
|
+
version: z.ZodNumber;
|
|
186
|
+
keyId: z.ZodString;
|
|
187
|
+
secret: z.ZodString;
|
|
188
|
+
shownOnce: z.ZodLiteral<true>;
|
|
189
|
+
}, z.core.$strip>;
|
|
190
|
+
export type CallbackEndpointCreated = z.infer<typeof callbackEndpointCreatedSchema>;
|
|
191
|
+
export declare const callbackSigningKeyRotationRequestSchema: z.ZodObject<{
|
|
192
|
+
overlapSeconds: z.ZodOptional<z.ZodNumber>;
|
|
193
|
+
}, z.core.$strip>;
|
|
194
|
+
export type CallbackSigningKeyRotationRequest = z.infer<typeof callbackSigningKeyRotationRequestSchema>;
|
|
195
|
+
export declare const callbackEndpointRotatedSchema: z.ZodObject<{
|
|
196
|
+
endpoint: z.ZodObject<{
|
|
197
|
+
createdAt: z.ZodString;
|
|
198
|
+
disabledAt: z.ZodOptional<z.ZodString>;
|
|
199
|
+
environmentKind: z.ZodEnum<{
|
|
200
|
+
test: "test";
|
|
201
|
+
live: "live";
|
|
202
|
+
}>;
|
|
203
|
+
id: z.ZodString;
|
|
204
|
+
lastVerificationAttemptAt: z.ZodOptional<z.ZodString>;
|
|
205
|
+
lastVerificationFailure: z.ZodOptional<z.ZodEnum<{
|
|
206
|
+
rate_limited: "rate_limited";
|
|
207
|
+
address_forbidden: "address_forbidden";
|
|
208
|
+
challenge_failed: "challenge_failed";
|
|
209
|
+
connection_failed: "connection_failed";
|
|
210
|
+
dns_unresolved: "dns_unresolved";
|
|
211
|
+
redirect_refused: "redirect_refused";
|
|
212
|
+
response_too_large: "response_too_large";
|
|
213
|
+
timed_out: "timed_out";
|
|
214
|
+
unexpected_status: "unexpected_status";
|
|
215
|
+
}>>;
|
|
216
|
+
project: z.ZodString;
|
|
217
|
+
signingKeys: z.ZodObject<{
|
|
218
|
+
current: z.ZodString;
|
|
219
|
+
next: z.ZodOptional<z.ZodObject<{
|
|
220
|
+
id: z.ZodString;
|
|
221
|
+
overlapEndsAt: z.ZodString;
|
|
222
|
+
}, z.core.$strip>>;
|
|
223
|
+
}, z.core.$strip>;
|
|
224
|
+
status: z.ZodEnum<{
|
|
225
|
+
verified: "verified";
|
|
226
|
+
pending: "pending";
|
|
227
|
+
disabled: "disabled";
|
|
228
|
+
}>;
|
|
229
|
+
updatedAt: z.ZodString;
|
|
230
|
+
url: z.ZodString;
|
|
231
|
+
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
232
|
+
version: z.ZodNumber;
|
|
233
|
+
}, z.core.$strip>;
|
|
234
|
+
keyId: z.ZodString;
|
|
235
|
+
secret: z.ZodString;
|
|
236
|
+
shownOnce: z.ZodLiteral<true>;
|
|
237
|
+
}, z.core.$strip>;
|
|
238
|
+
export type CallbackEndpointRotated = z.infer<typeof callbackEndpointRotatedSchema>;
|
|
239
|
+
export declare const callbackEndpointRequestSchema: z.ZodObject<{
|
|
240
|
+
url: z.ZodString;
|
|
241
|
+
}, z.core.$strip>;
|
|
242
|
+
export type CallbackEndpointRequest = z.infer<typeof callbackEndpointRequestSchema>;
|
|
243
|
+
export declare const CALLBACK_VERIFICATION_PROTOCOL_VERSION = "2026-08-05";
|
|
244
|
+
export declare const CALLBACK_VERIFICATION_TYPE = "callback.endpoint.verification";
|
|
245
|
+
/**
|
|
246
|
+
* Exact verification bytes sent to the receiver. The receiver validates the
|
|
247
|
+
* request signature and proves possession of the one-time secret by returning
|
|
248
|
+
* an HMAC of `challenge` in `Callback-Verification-Response`.
|
|
249
|
+
*/
|
|
250
|
+
export declare const callbackVerificationChallengeSchema: z.ZodObject<{
|
|
251
|
+
challenge: z.ZodString;
|
|
252
|
+
endpointId: z.ZodString;
|
|
253
|
+
type: z.ZodLiteral<"callback.endpoint.verification">;
|
|
254
|
+
version: z.ZodLiteral<"2026-08-05">;
|
|
255
|
+
}, z.core.$strip>;
|
|
256
|
+
export type CallbackVerificationChallenge = z.infer<typeof callbackVerificationChallengeSchema>;
|
|
257
|
+
export declare const CALLBACK_VERIFICATION_HEADERS: {
|
|
258
|
+
readonly challenge: "Callback-Verification-Challenge";
|
|
259
|
+
readonly requestSignature: "Callback-Verification-Signature";
|
|
260
|
+
readonly responseSignature: "Callback-Verification-Response";
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Machine-readable receiver contract for endpoint ownership verification.
|
|
264
|
+
*
|
|
265
|
+
* This is deliberately separate from W3-02's occurrence-delivery signature:
|
|
266
|
+
* the request proves control of a receiver before the endpoint may be used,
|
|
267
|
+
* while a delivery signature authenticates an occurrence body later. The
|
|
268
|
+
* generator publishes this object beside OpenAPI and the JSON Schema.
|
|
269
|
+
*/
|
|
270
|
+
export declare const CALLBACK_VERIFICATION_PROTOCOL: {
|
|
271
|
+
readonly purpose: "Prove that the receiver possesses the one-time endpoint secret before Greatwait marks the endpoint verified.";
|
|
272
|
+
readonly request: {
|
|
273
|
+
readonly bodyEncoding: "UTF-8 bytes of the compact JSON object in schema property order: challenge, endpointId, type, version.";
|
|
274
|
+
readonly contentType: "application/json";
|
|
275
|
+
readonly method: "POST";
|
|
276
|
+
readonly redirectPolicy: "manual; every 3xx response is refused";
|
|
277
|
+
readonly signature: {
|
|
278
|
+
readonly algorithm: "HMAC-SHA-256";
|
|
279
|
+
readonly format: "v1=<64 lowercase hexadecimal characters>";
|
|
280
|
+
readonly header: "Callback-Verification-Signature";
|
|
281
|
+
readonly input: "the exact request body bytes";
|
|
282
|
+
readonly key: "the one-time endpoint secret returned by REST endpoint creation";
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
readonly response: {
|
|
286
|
+
readonly body: "ignored after enforcing the 1024-byte response limit; return an empty body";
|
|
287
|
+
readonly proof: {
|
|
288
|
+
readonly algorithm: "HMAC-SHA-256";
|
|
289
|
+
readonly format: "v1=<64 lowercase hexadecimal characters>";
|
|
290
|
+
readonly header: "Callback-Verification-Response";
|
|
291
|
+
readonly input: "the UTF-8 bytes of the challenge string";
|
|
292
|
+
readonly key: "the same endpoint secret";
|
|
293
|
+
};
|
|
294
|
+
readonly status: "any 2xx status";
|
|
295
|
+
};
|
|
296
|
+
readonly testVector: {
|
|
297
|
+
readonly challenge: "cvc_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
|
298
|
+
readonly endpointId: "ep_00000000000000000000000000";
|
|
299
|
+
readonly exactBodyBase64: "eyJjaGFsbGVuZ2UiOiJjdmNfQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQSIsImVuZHBvaW50SWQiOiJlcF8wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCIsInR5cGUiOiJjYWxsYmFjay5lbmRwb2ludC52ZXJpZmljYXRpb24iLCJ2ZXJzaW9uIjoiMjAyNi0wOC0wNSJ9";
|
|
300
|
+
readonly requestSignature: "v1=0d24c7fed4d752411b88025a9923627b329e0eb9d53978a6ebcf92c0678c731e";
|
|
301
|
+
readonly responseSignature: "v1=efc690a23f1870930ff3388313162c0e06406902a7a4d3f9273ffe0abcef86bd";
|
|
302
|
+
readonly secret: "verification-vector-secret";
|
|
303
|
+
};
|
|
304
|
+
readonly version: "2026-08-05";
|
|
305
|
+
};
|