@greatwait/contracts 0.3.0 → 0.3.2
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/dist/attempt-diagnostics.d.ts +1 -1
- package/dist/attempt-diagnostics.js +13 -1
- package/dist/attempt-search.d.ts +2 -0
- package/dist/attempt-search.js +22 -19
- package/dist/authority.js +9 -9
- package/dist/billing.d.ts +46 -0
- package/dist/billing.js +29 -0
- package/dist/callback-safety.js +5 -1
- package/dist/configuration.d.ts +6 -2
- package/dist/configuration.js +93 -52
- package/dist/delivery.d.ts +13 -1
- package/dist/delivery.js +2 -0
- package/dist/effective-limits.d.ts +4 -4
- package/dist/endpoints.d.ts +29 -0
- package/dist/endpoints.js +57 -26
- package/dist/forecast.d.ts +2 -2
- package/dist/http-request.d.ts +12 -2
- package/dist/http-request.js +56 -24
- package/dist/identifiers.js +20 -20
- package/dist/index.d.ts +8 -7
- package/dist/index.js +8 -7
- package/dist/mcp.js +1 -0
- package/dist/operational-config.d.ts +174 -22
- package/dist/operational-config.js +213 -79
- package/dist/operations.d.ts +334 -52
- package/dist/operations.js +195 -34
- package/dist/project-notifications.d.ts +35 -9
- package/dist/project-notifications.js +43 -12
- package/dist/protocol.d.ts +28 -0
- package/dist/protocol.js +56 -33
- package/dist/schedule-selection.js +2 -2
- package/dist/scheduling-records.d.ts +106 -16
- package/dist/scheduling-records.js +36 -12
- package/dist/scheduling.d.ts +200 -43
- package/dist/scheduling.js +280 -131
- package/dist/service-mode.d.ts +88 -0
- package/dist/service-mode.js +130 -0
- package/dist/signatures.d.ts +6 -6
- package/dist/signatures.js +24 -24
- package/dist/stored-http.d.ts +18 -0
- package/dist/stored-http.js +106 -0
- package/dist/tenancy.d.ts +54 -30
- package/dist/tenancy.js +35 -17
- package/dist/time.js +7 -7
- package/dist/timing.d.ts +39 -0
- package/dist/timing.js +51 -0
- package/dist/zod-values.d.ts +1 -1
- package/dist/zod-values.js +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +1 -1
- package/generated/v1/examples/billing.noticesdismiss.request.json +3 -0
- package/generated/v1/examples/billing.noticesdismiss.response.json +6 -0
- package/generated/v1/examples/billing.reconcile.response.json +12 -0
- package/generated/v1/examples/billing.summary.response.json +12 -0
- package/generated/v1/examples/executions.list.response.json +1 -0
- package/generated/v1/examples/limits.read.response.json +1 -1
- package/generated/v1/examples/projectnotifications.rotateSigningKey.response.json +1 -0
- package/generated/v1/examples/projects.list.response.json +0 -6
- package/generated/v1/examples/projects.read.response.json +14 -0
- package/generated/v1/examples/schedules.list.response.json +1 -3
- package/generated/v1/examples/schedules.summary.response.json +174 -0
- package/generated/v1/examples/timing.summary.response.json +33 -1
- package/generated/v1/manifest.json +79 -2
- package/generated/v1/openapi.json +4084 -2023
- package/generated/v1/policy-matrix.json +22 -1
- package/generated/v1/schemas/attempts.list.response.json +10 -0
- package/generated/v1/schemas/attempts.read.response.json +10 -0
- package/generated/v1/schemas/attempts.search.response.json +4 -0
- package/generated/v1/schemas/billing.notices.query.json +4 -0
- package/generated/v1/schemas/billing.noticesdismiss.request.json +12 -0
- package/generated/v1/schemas/billing.noticesdismiss.response.json +22 -0
- package/generated/v1/schemas/billing.reconcile.response.json +43 -0
- package/generated/v1/schemas/billing.summary.response.json +43 -0
- package/generated/v1/schemas/endpoints.list.query.json +15 -0
- package/generated/v1/schemas/executions.list.response.json +4 -0
- package/generated/v1/schemas/occurrences.list.response.json +4 -0
- package/generated/v1/schemas/occurrences.read.response.json +4 -0
- package/generated/v1/schemas/occurrences.redeliver.response.json +10 -0
- package/generated/v1/schemas/projectnotifications.read.response.json +4 -0
- package/generated/v1/schemas/projectnotifications.rotateSigningKey.response.json +4 -0
- package/generated/v1/schemas/projectnotifications.update.request.json +41 -17
- package/generated/v1/schemas/projectnotifications.update.response.json +4 -0
- package/generated/v1/schemas/projects.list.response.json +0 -27
- package/generated/v1/schemas/projects.read.response-headers.json +11 -0
- package/generated/v1/schemas/projects.read.response.json +79 -0
- package/generated/v1/schemas/schedules.archive.response.json +8 -0
- package/generated/v1/schemas/schedules.cancel.response.json +8 -0
- package/generated/v1/schemas/schedules.create.request.json +1 -1
- package/generated/v1/schemas/schedules.create.response.json +8 -0
- package/generated/v1/schemas/schedules.list.query.json +6 -0
- package/generated/v1/schemas/schedules.list.response.json +4 -0
- package/generated/v1/schemas/schedules.pause.response.json +8 -0
- package/generated/v1/schemas/schedules.read.response.json +8 -0
- package/generated/v1/schemas/schedules.replace.request.json +1 -1
- package/generated/v1/schemas/schedules.replace.response.json +8 -0
- package/generated/v1/schemas/schedules.resume.response.json +8 -0
- package/generated/v1/schemas/schedules.summary.query.json +11 -0
- package/generated/v1/schemas/schedules.summary.response.json +144 -0
- package/generated/v1/schemas/timing.summary.response.json +69 -0
- package/generated/v1/snippets/billing.noticesdismiss.json +6 -0
- package/generated/v1/snippets/projectnotifications.rotateSigningKey.json +1 -1
- package/generated/v1/snippets/projects.read.json +6 -0
- package/generated/v1/snippets/schedules.summary.json +6 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "./zod.js";
|
|
2
2
|
import { environmentKindSchema } from "./authority.js";
|
|
3
|
-
import { callbackSigningKeyIdSchema, occurrenceIdSchema, projectIdSchema, scheduleIdSchema, } from "./identifiers.js";
|
|
3
|
+
import { callbackSigningKeyIdSchema, endpointIdSchema, occurrenceIdSchema, projectIdSchema, scheduleIdSchema, } from "./identifiers.js";
|
|
4
4
|
import { memberIdSchema } from "./members.js";
|
|
5
5
|
import { timestampSchema } from "./time.js";
|
|
6
6
|
import { pageRequestSchema, requiredIdempotencyRequestHeaderSchema, } from "./protocol.js";
|
|
@@ -23,13 +23,26 @@ export const notificationEmailSettingsSchema = z.strictObject({
|
|
|
23
23
|
scheduleKinds: z.enum(["both", "one-shot", "recurring"]),
|
|
24
24
|
});
|
|
25
25
|
export const statusWebhookEventSchema = z.enum(["failed"]);
|
|
26
|
+
const statusWebhookEventsSchema = z
|
|
27
|
+
.array(statusWebhookEventSchema)
|
|
28
|
+
.min(1)
|
|
29
|
+
.max(1)
|
|
30
|
+
.refine((events) => new Set(events).size === events.length, "events must be unique");
|
|
31
|
+
/**
|
|
32
|
+
* The earlier configuration: a bare URL. Still accepted (W9-84): the endpoint
|
|
33
|
+
* at that URL is found or created, as endpoints.ensure does, and linked.
|
|
34
|
+
*/
|
|
26
35
|
export const statusWebhookConfigurationSchema = z.strictObject({
|
|
27
36
|
url: z.string().url().max(2_048),
|
|
28
|
-
events:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
events: statusWebhookEventsSchema,
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* The status webhook's destination (W9-84): a callback endpoint in this
|
|
41
|
+
* project and environment, whose URL, headers and signing keys apply.
|
|
42
|
+
*/
|
|
43
|
+
export const statusWebhookEndpointConfigurationSchema = z.strictObject({
|
|
44
|
+
endpoint: endpointIdSchema,
|
|
45
|
+
events: statusWebhookEventsSchema,
|
|
33
46
|
});
|
|
34
47
|
export const projectNotificationSettingsSchema = z.strictObject({
|
|
35
48
|
project: projectIdSchema,
|
|
@@ -38,6 +51,9 @@ export const projectNotificationSettingsSchema = z.strictObject({
|
|
|
38
51
|
email: notificationEmailSettingsSchema,
|
|
39
52
|
statusWebhook: statusWebhookConfigurationSchema
|
|
40
53
|
.extend({
|
|
54
|
+
/** The destination endpoint; absent only for a URL saved before W9-84 without a key. */
|
|
55
|
+
endpoint: endpointIdSchema.optional(),
|
|
56
|
+
/** The key that signs: the endpoint's next key while one is staged, else its current one. */
|
|
41
57
|
signingKey: z.strictObject({ id: callbackSigningKeyIdSchema }).optional(),
|
|
42
58
|
revision: z.number().int().positive(),
|
|
43
59
|
})
|
|
@@ -47,7 +63,13 @@ export const projectNotificationSettingsUpdateRequestSchema = z
|
|
|
47
63
|
.strictObject({
|
|
48
64
|
expectedRevision: z.number().int().positive(),
|
|
49
65
|
email: notificationEmailSettingsSchema.optional(),
|
|
50
|
-
statusWebhook:
|
|
66
|
+
statusWebhook: z
|
|
67
|
+
.union([
|
|
68
|
+
statusWebhookEndpointConfigurationSchema,
|
|
69
|
+
statusWebhookConfigurationSchema,
|
|
70
|
+
])
|
|
71
|
+
.nullable()
|
|
72
|
+
.optional(),
|
|
51
73
|
})
|
|
52
74
|
.refine((request) => request.email !== undefined || request.statusWebhook !== undefined, "choose settings to change");
|
|
53
75
|
export const statusSigningKeyRequestSchema = z.strictObject({
|
|
@@ -57,6 +79,11 @@ export const statusSigningKeyCreatedSchema = z.strictObject({
|
|
|
57
79
|
settings: projectNotificationSettingsSchema,
|
|
58
80
|
keyId: callbackSigningKeyIdSchema,
|
|
59
81
|
secret: z.string().min(1),
|
|
82
|
+
/**
|
|
83
|
+
* Kept for compatibility (W9-84). The secret is the destination endpoint's,
|
|
84
|
+
* so a signed-in member can also reveal it on the endpoint's page, as for
|
|
85
|
+
* every endpoint secret; `shownOnce` no longer means this is the only copy.
|
|
86
|
+
*/
|
|
60
87
|
shownOnce: z.literal(true),
|
|
61
88
|
});
|
|
62
89
|
/** Safe notification payload: no customer request or response content. */
|
|
@@ -144,6 +171,8 @@ export const PROJECT_NOTIFICATION_OPERATIONS = defineOperations([
|
|
|
144
171
|
"revision_conflict",
|
|
145
172
|
"idempotency_key_reused",
|
|
146
173
|
"rate_limited",
|
|
174
|
+
"scope_missing",
|
|
175
|
+
"state_conflict",
|
|
147
176
|
],
|
|
148
177
|
requestHeaders: requiredIdempotencyRequestHeaderSchema,
|
|
149
178
|
request: projectNotificationSettingsUpdateRequestSchema,
|
|
@@ -161,7 +190,7 @@ export const PROJECT_NOTIFICATION_OPERATIONS = defineOperations([
|
|
|
161
190
|
: "Update delivery notification settings",
|
|
162
191
|
description: globals.GREATWAIT_RUNTIME_CONTRACTS_ONLY
|
|
163
192
|
? ""
|
|
164
|
-
: "An admin updates this project's environment preferences at an expected revision. Selected recipients must be current organization members; arbitrary email addresses are not accepted.
|
|
193
|
+
: "An admin updates this project's environment preferences at an expected revision. Selected recipients must be current organization members; arbitrary email addresses are not accepted. The status webhook names its destination as `endpoint`, an enabled callback endpoint in this project and environment, which needs `endpoints:read`: failure events go to its URL with its headers, signed with its key, and delivery starts at once. A `url` instead is the earlier form: the endpoint at that address is found or created (the endpoints.ensure rules; creating needs `endpoints:write`) and linked. Without the scope a form needs, the request is refused as `scope_missing`. Null disables the status webhook. No signing secret is returned; a signed-in member reveals it on the endpoint's page. Failed means final unsuccessful settlement. Redelivery never repeats it. Failed-event webhook calls and their retries are free. Every failed occurrence is emailed separately; no summary window suppresses failures.",
|
|
165
194
|
},
|
|
166
195
|
{
|
|
167
196
|
...common,
|
|
@@ -172,14 +201,15 @@ export const PROJECT_NOTIFICATION_OPERATIONS = defineOperations([
|
|
|
172
201
|
mutates: true,
|
|
173
202
|
mcp: {
|
|
174
203
|
kind: "unavailable",
|
|
175
|
-
reason: "
|
|
204
|
+
reason: "Rotating returns a signing secret, and MCP has no negotiated secure-result channel that keeps it out of ordinary tool history. Choose the status webhook's endpoint with projectnotifications_update; reveal or rotate that endpoint's key on its page in the dashboard, or with endpoints.rotateSigningKey through an authenticated REST/SDK/CLI client.",
|
|
176
205
|
},
|
|
177
|
-
scopes: ["projects:administer"],
|
|
206
|
+
scopes: ["projects:administer", "endpoints:write"],
|
|
178
207
|
problems: [
|
|
179
208
|
...common.problems,
|
|
180
209
|
"revision_conflict",
|
|
181
210
|
"state_conflict",
|
|
182
211
|
"capability_not_configured",
|
|
212
|
+
"scope_missing",
|
|
183
213
|
],
|
|
184
214
|
request: statusSigningKeyRequestSchema,
|
|
185
215
|
requestExample: globals.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES
|
|
@@ -197,6 +227,7 @@ export const PROJECT_NOTIFICATION_OPERATIONS = defineOperations([
|
|
|
197
227
|
statusWebhook: {
|
|
198
228
|
url: "https://hooks.example.com/status",
|
|
199
229
|
events: ["failed"],
|
|
230
|
+
endpoint: "ep_01h8xyz9k2m4n6p8r0t2v4w6y8",
|
|
200
231
|
revision: 2,
|
|
201
232
|
signingKey: { id: "csk_01h8xyz9k2m4n6p8r0t2v4w6y8" },
|
|
202
233
|
},
|
|
@@ -207,10 +238,10 @@ export const PROJECT_NOTIFICATION_OPERATIONS = defineOperations([
|
|
|
207
238
|
},
|
|
208
239
|
summary: globals.GREATWAIT_API_REQUEST_REGISTRY
|
|
209
240
|
? ""
|
|
210
|
-
: "
|
|
241
|
+
: "Rotate the status webhook endpoint's signing key",
|
|
211
242
|
description: globals.GREATWAIT_RUNTIME_CONTRACTS_ONLY
|
|
212
243
|
? ""
|
|
213
|
-
: "
|
|
244
|
+
: "The earlier form, kept for existing clients: at an expected revision, rotate the signing key of the configured status webhook's endpoint exactly as endpoints.rotateSigningKey does with its default overlap. The key is the endpoint's and is shared with every schedule using it, so this also needs `endpoints:write`; without it the request is refused as `scope_missing`. A webhook saved as a bare URL is first linked to the endpoint at that address. New deliveries are signed with the new key at once, and receivers keep accepting the previous key until the overlap ends. The secret appears in this successful response and, like every endpoint secret, is also revealable by a signed-in member on the endpoint's page; `shownOnce` is kept for compatibility. The request is not automatically replayable; stale retries are refused. The signature covers the exact emitted body bytes.",
|
|
214
245
|
},
|
|
215
246
|
{
|
|
216
247
|
...common,
|
package/dist/protocol.d.ts
CHANGED
|
@@ -39,6 +39,18 @@ export type PageRequest = z.infer<typeof pageRequestSchema>;
|
|
|
39
39
|
*/
|
|
40
40
|
export declare const SCHEDULE_ORDERS: readonly ["created", "due"];
|
|
41
41
|
export type ScheduleOrder = (typeof SCHEDULE_ORDERS)[number];
|
|
42
|
+
/**
|
|
43
|
+
* Which way a schedules listing walks its order (W9-80, FXO-3446).
|
|
44
|
+
*
|
|
45
|
+
* `asc` is what every listing has always done and keeps by default, so a
|
|
46
|
+
* client that never heard of this parameter sees nothing change. `desc` is
|
|
47
|
+
* newest-created first under `created` (the newest schedule is one row away
|
|
48
|
+
* rather than a whole book away) and latest-due first under `due`. A cursor is
|
|
49
|
+
* a position in one direction only: one issued walking `desc` is refused under
|
|
50
|
+
* `asc`, and the other way round.
|
|
51
|
+
*/
|
|
52
|
+
export declare const SCHEDULE_DIRECTIONS: readonly ["asc", "desc"];
|
|
53
|
+
export type ScheduleDirection = (typeof SCHEDULE_DIRECTIONS)[number];
|
|
42
54
|
/**
|
|
43
55
|
* A schedules listing: the page, optionally one endpoint, and how to order it.
|
|
44
56
|
*
|
|
@@ -58,6 +70,10 @@ export declare const scheduleListRequestSchema: import("zod").ZodObject<{
|
|
|
58
70
|
due: "due";
|
|
59
71
|
created: "created";
|
|
60
72
|
}>>;
|
|
73
|
+
direction: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
74
|
+
asc: "asc";
|
|
75
|
+
desc: "desc";
|
|
76
|
+
}>>;
|
|
61
77
|
external_identifier: import("zod").ZodOptional<import("zod").ZodString>;
|
|
62
78
|
tag: import("zod").ZodOptional<import("zod").ZodString>;
|
|
63
79
|
status: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
@@ -245,6 +261,18 @@ export type ScheduleListRequestParse = {
|
|
|
245
261
|
readonly ok: false;
|
|
246
262
|
readonly errors: readonly FieldError[];
|
|
247
263
|
};
|
|
264
|
+
/**
|
|
265
|
+
* Any listing request whose fields are page parameters plus string filters,
|
|
266
|
+
* read from a query string under the same rules as {@link parsePageRequest}
|
|
267
|
+
* (W9-80: the endpoints listing's filters).
|
|
268
|
+
*/
|
|
269
|
+
export declare function parseListingRequest<TSchema extends z.ZodTypeAny>(query: URLSearchParams, schema: TSchema): {
|
|
270
|
+
readonly ok: true;
|
|
271
|
+
readonly page: z.infer<TSchema>;
|
|
272
|
+
} | {
|
|
273
|
+
readonly ok: false;
|
|
274
|
+
readonly errors: readonly FieldError[];
|
|
275
|
+
};
|
|
248
276
|
/** A schedules listing request: the page, and the endpoint filter if given. */
|
|
249
277
|
export declare function parseScheduleListRequest(query: URLSearchParams): ScheduleListRequestParse;
|
|
250
278
|
export type HistoryPageRequestParse = {
|
package/dist/protocol.js
CHANGED
|
@@ -16,7 +16,7 @@ import { timestampSchema } from "./time.js";
|
|
|
16
16
|
* exactly what they were given.
|
|
17
17
|
*/
|
|
18
18
|
export const PAGE_SIZE = PUBLIC_PAGE_SIZE;
|
|
19
|
-
export const pageRequestSchema = z.object({
|
|
19
|
+
export const pageRequestSchema = /* @__PURE__ */ (() => z.object({
|
|
20
20
|
cursor: z.string().min(1).optional(),
|
|
21
21
|
limit: z
|
|
22
22
|
.number()
|
|
@@ -24,7 +24,7 @@ export const pageRequestSchema = z.object({
|
|
|
24
24
|
.min(PAGE_SIZE.min)
|
|
25
25
|
.max(PAGE_SIZE.max)
|
|
26
26
|
.default(PAGE_SIZE.default),
|
|
27
|
-
});
|
|
27
|
+
}))();
|
|
28
28
|
/**
|
|
29
29
|
* A schedules listing: the page, and optionally one endpoint to keep to.
|
|
30
30
|
*
|
|
@@ -43,6 +43,17 @@ export const pageRequestSchema = z.object({
|
|
|
43
43
|
* creation instant.
|
|
44
44
|
*/
|
|
45
45
|
export const SCHEDULE_ORDERS = ["created", "due"];
|
|
46
|
+
/**
|
|
47
|
+
* Which way a schedules listing walks its order (W9-80, FXO-3446).
|
|
48
|
+
*
|
|
49
|
+
* `asc` is what every listing has always done and keeps by default, so a
|
|
50
|
+
* client that never heard of this parameter sees nothing change. `desc` is
|
|
51
|
+
* newest-created first under `created` (the newest schedule is one row away
|
|
52
|
+
* rather than a whole book away) and latest-due first under `due`. A cursor is
|
|
53
|
+
* a position in one direction only: one issued walking `desc` is refused under
|
|
54
|
+
* `asc`, and the other way round.
|
|
55
|
+
*/
|
|
56
|
+
export const SCHEDULE_DIRECTIONS = ["asc", "desc"];
|
|
46
57
|
/**
|
|
47
58
|
* A schedules listing: the page, optionally one endpoint, and how to order it.
|
|
48
59
|
*
|
|
@@ -55,10 +66,14 @@ export const SCHEDULE_ORDERS = ["created", "due"];
|
|
|
55
66
|
* a schedule with nothing on the books matches no `dueBefore`, because it has
|
|
56
67
|
* no instant to compare and inventing one either way would be a guess.
|
|
57
68
|
*/
|
|
58
|
-
export const scheduleListRequestSchema = pageRequestSchema.extend({
|
|
69
|
+
export const scheduleListRequestSchema = /* @__PURE__ */ (() => pageRequestSchema.extend({
|
|
59
70
|
...scheduleSelectionSchema.shape,
|
|
60
71
|
order: z.enum(SCHEDULE_ORDERS).default("created"),
|
|
61
|
-
|
|
72
|
+
direction: z
|
|
73
|
+
.enum(SCHEDULE_DIRECTIONS)
|
|
74
|
+
.default("asc")
|
|
75
|
+
.describe("asc (default) walks the order oldest-created or soonest-due first; desc walks it newest-created or latest-due first. A cursor continues only in the direction that issued it."),
|
|
76
|
+
}))();
|
|
62
77
|
/**
|
|
63
78
|
* Which end of a history a page walks from.
|
|
64
79
|
*
|
|
@@ -70,9 +85,9 @@ export const scheduleListRequestSchema = pageRequestSchema.extend({
|
|
|
70
85
|
*/
|
|
71
86
|
export const HISTORY_ORDERS = ["oldest", "newest"];
|
|
72
87
|
/** A page request over a history, which may be walked from either end. */
|
|
73
|
-
export const historyPageRequestSchema = pageRequestSchema.extend({
|
|
88
|
+
export const historyPageRequestSchema = /* @__PURE__ */ (() => pageRequestSchema.extend({
|
|
74
89
|
order: z.enum(HISTORY_ORDERS).default("oldest"),
|
|
75
|
-
});
|
|
90
|
+
}))();
|
|
76
91
|
/**
|
|
77
92
|
* A page of results.
|
|
78
93
|
*
|
|
@@ -82,14 +97,14 @@ export const historyPageRequestSchema = pageRequestSchema.extend({
|
|
|
82
97
|
* stale data as fact. `authoritative` means the answer came from the owning
|
|
83
98
|
* partition; `projected` means it may lag and carries the age.
|
|
84
99
|
*/
|
|
85
|
-
export const freshnessSchema = z.discriminatedUnion("kind", [
|
|
100
|
+
export const freshnessSchema = /* @__PURE__ */ (() => z.discriminatedUnion("kind", [
|
|
86
101
|
z.object({ kind: z.literal("authoritative") }),
|
|
87
102
|
z.object({
|
|
88
103
|
asOf: timestampSchema,
|
|
89
104
|
kind: z.literal("projected"),
|
|
90
105
|
lagSeconds: z.number().int().nonnegative(),
|
|
91
106
|
}),
|
|
92
|
-
]);
|
|
107
|
+
]))();
|
|
93
108
|
/**
|
|
94
109
|
* The `projected` arm alone, for a response that is never authoritative.
|
|
95
110
|
*
|
|
@@ -100,11 +115,11 @@ export const freshnessSchema = z.discriminatedUnion("kind", [
|
|
|
100
115
|
* taken, were unreachable without narrowing that no consumer could justify.
|
|
101
116
|
* Naming the narrower shape moves the claim into the type.
|
|
102
117
|
*/
|
|
103
|
-
export const projectedFreshnessSchema = z.object({
|
|
118
|
+
export const projectedFreshnessSchema = /* @__PURE__ */ (() => z.object({
|
|
104
119
|
asOf: timestampSchema,
|
|
105
120
|
kind: z.literal("projected"),
|
|
106
121
|
lagSeconds: z.number().int().nonnegative(),
|
|
107
|
-
});
|
|
122
|
+
}))();
|
|
108
123
|
export function pageSchema(item) {
|
|
109
124
|
return z.object({
|
|
110
125
|
data: z.array(item),
|
|
@@ -287,6 +302,14 @@ function parametersOf(schema) {
|
|
|
287
302
|
export function parsePageRequest(query) {
|
|
288
303
|
return parseListing(query, pageRequestSchema);
|
|
289
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Any listing request whose fields are page parameters plus string filters,
|
|
307
|
+
* read from a query string under the same rules as {@link parsePageRequest}
|
|
308
|
+
* (W9-80: the endpoints listing's filters).
|
|
309
|
+
*/
|
|
310
|
+
export function parseListingRequest(query, schema) {
|
|
311
|
+
return parseListing(query, schema);
|
|
312
|
+
}
|
|
290
313
|
/** A schedules listing request: the page, and the endpoint filter if given. */
|
|
291
314
|
export function parseScheduleListRequest(query) {
|
|
292
315
|
return parseListing(query, scheduleListRequestSchema);
|
|
@@ -337,7 +360,7 @@ function parseListing(query, schema) {
|
|
|
337
360
|
* `version_conflict` rather than silently overwriting — a cancel racing a
|
|
338
361
|
* replace must not resolve by luck.
|
|
339
362
|
*/
|
|
340
|
-
export const versionSchema = z.number().int().positive();
|
|
363
|
+
export const versionSchema = /* @__PURE__ */ (() => z.number().int().positive())();
|
|
341
364
|
/**
|
|
342
365
|
* A strong entity tag over a version: a quoted decimal, and nothing else.
|
|
343
366
|
*
|
|
@@ -383,10 +406,10 @@ export function fromETag(etag) {
|
|
|
383
406
|
* refinement is the extra strictness the OpenAPI preamble already discloses
|
|
384
407
|
* that a described schema does not capture.
|
|
385
408
|
*/
|
|
386
|
-
export const etagSchema = z
|
|
409
|
+
export const etagSchema = /* @__PURE__ */ (() => z
|
|
387
410
|
.string()
|
|
388
411
|
.regex(ETAG_PATTERN, ETAG_MESSAGE)
|
|
389
|
-
.refine((value) => fromETag(value) !== undefined, ETAG_MESSAGE);
|
|
412
|
+
.refine((value) => fromETag(value) !== undefined, ETAG_MESSAGE))();
|
|
390
413
|
/* -------------------------------------------------------------------------- */
|
|
391
414
|
/* Idempotency */
|
|
392
415
|
/* -------------------------------------------------------------------------- */
|
|
@@ -400,11 +423,11 @@ export const etagSchema = z
|
|
|
400
423
|
* silent second write — that distinction is the whole point, and the legacy
|
|
401
424
|
* scheduler had no equivalent.
|
|
402
425
|
*/
|
|
403
|
-
export const idempotencyKeySchema = z
|
|
426
|
+
export const idempotencyKeySchema = /* @__PURE__ */ (() => z
|
|
404
427
|
.string()
|
|
405
428
|
.min(16, "must be at least 16 characters so keys do not collide by accident")
|
|
406
429
|
.max(255)
|
|
407
|
-
.regex(/^[\x20-\x7e]+$/u, "must be printable ASCII");
|
|
430
|
+
.regex(/^[\x20-\x7e]+$/u, "must be printable ASCII"))();
|
|
408
431
|
/**
|
|
409
432
|
* The scope a key was used in. Carried on the receipt rather than assumed,
|
|
410
433
|
* because an implementation that keys its receipt store on the idempotency key
|
|
@@ -412,13 +435,13 @@ export const idempotencyKeySchema = z
|
|
|
412
435
|
* send the same key. The scope is part of the record so that mistake cannot be
|
|
413
436
|
* made silently.
|
|
414
437
|
*/
|
|
415
|
-
export const idempotencyScopeSchema = z.object({
|
|
438
|
+
export const idempotencyScopeSchema = /* @__PURE__ */ (() => z.object({
|
|
416
439
|
environment: environmentIdSchema,
|
|
417
440
|
operation: z.string().min(1),
|
|
418
441
|
organization: organizationIdSchema,
|
|
419
442
|
project: projectIdSchema,
|
|
420
|
-
});
|
|
421
|
-
export const idempotencyReceiptSchema = z.object({
|
|
443
|
+
}))();
|
|
444
|
+
export const idempotencyReceiptSchema = /* @__PURE__ */ (() => z.object({
|
|
422
445
|
/**
|
|
423
446
|
* Hash of the canonical request the key was first used with. Canonical
|
|
424
447
|
* means: the operation name, then the request body serialized with object
|
|
@@ -431,7 +454,7 @@ export const idempotencyReceiptSchema = z.object({
|
|
|
431
454
|
replayed: z.boolean(),
|
|
432
455
|
scope: idempotencyScopeSchema,
|
|
433
456
|
storedAt: timestampSchema,
|
|
434
|
-
});
|
|
457
|
+
}))();
|
|
435
458
|
/**
|
|
436
459
|
* The canonical form of a request, as the receipt's `requestFingerprint`
|
|
437
460
|
* describes it: the operation name, then the body with object keys sorted and
|
|
@@ -535,9 +558,9 @@ export const CONCURRENCY_HEADERS = {
|
|
|
535
558
|
ifMatch: "If-Match",
|
|
536
559
|
replayed: "Idempotency-Replayed",
|
|
537
560
|
};
|
|
538
|
-
export const idempotencyRequestHeaderSchema = z.object({
|
|
561
|
+
export const idempotencyRequestHeaderSchema = /* @__PURE__ */ (() => z.object({
|
|
539
562
|
[CONCURRENCY_HEADERS.idempotencyKey]: idempotencyKeySchema.optional(),
|
|
540
|
-
});
|
|
563
|
+
}))();
|
|
541
564
|
/**
|
|
542
565
|
* A write for which idempotency is mandatory, rather than an optional
|
|
543
566
|
* protection a caller may opt into.
|
|
@@ -547,12 +570,12 @@ export const idempotencyRequestHeaderSchema = z.object({
|
|
|
547
570
|
* `idempotencyRequestHeaderSchema` lets schedule creation retain its published
|
|
548
571
|
* optional behavior without weakening the redelivery promise.
|
|
549
572
|
*/
|
|
550
|
-
export const requiredIdempotencyRequestHeaderSchema = z.object({
|
|
573
|
+
export const requiredIdempotencyRequestHeaderSchema = /* @__PURE__ */ (() => z.object({
|
|
551
574
|
[CONCURRENCY_HEADERS.idempotencyKey]: idempotencyKeySchema,
|
|
552
|
-
});
|
|
553
|
-
export const conditionalRequestHeaderSchema = z.object({
|
|
575
|
+
}))();
|
|
576
|
+
export const conditionalRequestHeaderSchema = /* @__PURE__ */ (() => z.object({
|
|
554
577
|
[CONCURRENCY_HEADERS.ifMatch]: etagSchema.optional(),
|
|
555
|
-
});
|
|
578
|
+
}))();
|
|
556
579
|
/**
|
|
557
580
|
* A conditional write that refuses an unversioned request.
|
|
558
581
|
*
|
|
@@ -561,18 +584,18 @@ export const conditionalRequestHeaderSchema = z.object({
|
|
|
561
584
|
* silently accepting a missing precondition would let a stale General page
|
|
562
585
|
* overwrite a newer decision.
|
|
563
586
|
*/
|
|
564
|
-
export const requiredConditionalRequestHeaderSchema = z.object({
|
|
587
|
+
export const requiredConditionalRequestHeaderSchema = /* @__PURE__ */ (() => z.object({
|
|
565
588
|
[CONCURRENCY_HEADERS.ifMatch]: etagSchema,
|
|
566
|
-
});
|
|
589
|
+
}))();
|
|
567
590
|
/**
|
|
568
591
|
* Required rather than optional, deliberately: an operation that declares this
|
|
569
592
|
* promises the header on every success, and a client that has to test for its
|
|
570
593
|
* presence before making a conditional write will write the untested branch
|
|
571
594
|
* wrong.
|
|
572
595
|
*/
|
|
573
|
-
export const versionResponseHeaderSchema = z.object({
|
|
596
|
+
export const versionResponseHeaderSchema = /* @__PURE__ */ (() => z.object({
|
|
574
597
|
[CONCURRENCY_HEADERS.etag]: etagSchema,
|
|
575
|
-
});
|
|
598
|
+
}))();
|
|
576
599
|
/**
|
|
577
600
|
* What a replayed write answers with, on top of the version.
|
|
578
601
|
*
|
|
@@ -588,11 +611,11 @@ export const versionResponseHeaderSchema = z.object({
|
|
|
588
611
|
* header is the ordinary case, and a client that has to read a header to learn
|
|
589
612
|
* nothing happened is a client that will not read it.
|
|
590
613
|
*/
|
|
591
|
-
export const replayedResponseHeaderSchema = z.object({
|
|
614
|
+
export const replayedResponseHeaderSchema = /* @__PURE__ */ (() => z.object({
|
|
592
615
|
[CONCURRENCY_HEADERS.etag]: etagSchema,
|
|
593
616
|
[CONCURRENCY_HEADERS.replayed]: z.literal("true").optional(),
|
|
594
|
-
});
|
|
617
|
+
}))();
|
|
595
618
|
/** Replay marker for an idempotent create whose result has no ETag. */
|
|
596
|
-
export const idempotencyReplayResponseHeaderSchema = z.object({
|
|
619
|
+
export const idempotencyReplayResponseHeaderSchema = /* @__PURE__ */ (() => z.object({
|
|
597
620
|
[CONCURRENCY_HEADERS.replayed]: z.literal("true").optional(),
|
|
598
|
-
});
|
|
621
|
+
}))();
|
|
@@ -3,7 +3,7 @@ import { endpointIdSchema, scheduleIdSchema } from "./identifiers.js";
|
|
|
3
3
|
import { externalIdentifierSchema, scheduleTagSchema, } from "./host-correlation.js";
|
|
4
4
|
import { timestampSchema } from "./time.js";
|
|
5
5
|
/** Shared schedule predicates. Every populated field intersects before paging. */
|
|
6
|
-
export const scheduleSelectionSchema = z.object({
|
|
6
|
+
export const scheduleSelectionSchema = /* @__PURE__ */ (() => z.object({
|
|
7
7
|
external_identifier: externalIdentifierSchema.optional(),
|
|
8
8
|
tag: scheduleTagSchema.optional(),
|
|
9
9
|
status: z.enum(["active", "paused", "cancelled", "completed"]).optional(),
|
|
@@ -18,7 +18,7 @@ export const scheduleSelectionSchema = z.object({
|
|
|
18
18
|
schedule: scheduleIdSchema.optional(),
|
|
19
19
|
dueAfter: timestampSchema.optional(),
|
|
20
20
|
dueBefore: timestampSchema.optional(),
|
|
21
|
-
});
|
|
21
|
+
}))();
|
|
22
22
|
/** Canonical predicate shape for lists, cursor bindings and bulk selections. */
|
|
23
23
|
export function normalizeScheduleSelection(selection) {
|
|
24
24
|
const text = selection.text?.trim();
|