@greatwait/contracts 0.1.0-alpha.6 → 0.1.0-alpha.8

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.
Files changed (67) hide show
  1. package/README.md +1 -1
  2. package/dist/attempt-diagnostics.d.ts +8 -0
  3. package/dist/attempt-diagnostics.js +68 -0
  4. package/dist/billing.d.ts +12 -10
  5. package/dist/billing.js +14 -4
  6. package/dist/delivery.d.ts +17 -40
  7. package/dist/delivery.js +12 -37
  8. package/dist/effective-limits.d.ts +4 -4
  9. package/dist/endpoints.d.ts +6 -6
  10. package/dist/first-value-journey.js +4 -4
  11. package/dist/identity.d.ts +3 -3
  12. package/dist/index.d.ts +3 -1
  13. package/dist/index.js +3 -1
  14. package/dist/mcp.d.ts +1 -1
  15. package/dist/members.d.ts +4 -4
  16. package/dist/operations.d.ts +338 -103
  17. package/dist/operations.js +3 -1
  18. package/dist/policy.d.ts +5 -4
  19. package/dist/policy.js +5 -4
  20. package/dist/project-notifications.d.ts +238 -0
  21. package/dist/project-notifications.js +236 -0
  22. package/dist/scheduling-records.d.ts +112 -8
  23. package/dist/scheduling.d.ts +253 -22
  24. package/dist/scheduling.js +51 -9
  25. package/dist/signatures.d.ts +1 -1
  26. package/dist/test-sink.d.ts +27 -41
  27. package/dist/test-sink.js +12 -31
  28. package/dist/workspace.d.ts +4 -4
  29. package/generated/v1/callback-receiver.json +4 -4
  30. package/generated/v1/examples/projectnotifications.read.response.json +12 -0
  31. package/generated/v1/examples/projectnotifications.rotateSigningKey.request.json +3 -0
  32. package/generated/v1/examples/projectnotifications.rotateSigningKey.response.json +25 -0
  33. package/generated/v1/examples/projectnotifications.update.request.json +10 -0
  34. package/generated/v1/examples/projectnotifications.update.response.json +12 -0
  35. package/generated/v1/examples/statusdeliveries.list.response.json +3 -0
  36. package/generated/v1/first-value-journey.json +4 -4
  37. package/generated/v1/manifest.json +110 -1
  38. package/generated/v1/openapi.json +3655 -333
  39. package/generated/v1/policy-matrix.json +28 -0
  40. package/generated/v1/schemas/attempts.list.response.json +105 -0
  41. package/generated/v1/schemas/attempts.read.response.json +105 -0
  42. package/generated/v1/schemas/billing.notices.response.json +17 -6
  43. package/generated/v1/schemas/billing.purchase.request.json +4 -0
  44. package/generated/v1/schemas/occurrences.redeliver.response.json +105 -0
  45. package/generated/v1/schemas/projectnotifications.read.response.json +101 -0
  46. package/generated/v1/schemas/projectnotifications.rotateSigningKey.request.json +13 -0
  47. package/generated/v1/schemas/projectnotifications.rotateSigningKey.response.json +119 -0
  48. package/generated/v1/schemas/projectnotifications.update.request-headers.json +13 -0
  49. package/generated/v1/schemas/projectnotifications.update.request.json +90 -0
  50. package/generated/v1/schemas/projectnotifications.update.response.json +101 -0
  51. package/generated/v1/schemas/schedules.archive.response.json +50 -0
  52. package/generated/v1/schemas/schedules.cancel.response.json +50 -0
  53. package/generated/v1/schemas/schedules.create.request.json +14 -0
  54. package/generated/v1/schemas/schedules.create.response.json +50 -0
  55. package/generated/v1/schemas/schedules.list.response.json +50 -0
  56. package/generated/v1/schemas/schedules.pause.response.json +50 -0
  57. package/generated/v1/schemas/schedules.read.response.json +50 -0
  58. package/generated/v1/schemas/schedules.replace.request.json +14 -0
  59. package/generated/v1/schemas/schedules.replace.response.json +50 -0
  60. package/generated/v1/schemas/schedules.resume.response.json +50 -0
  61. package/generated/v1/schemas/statusdeliveries.list.query.json +16 -0
  62. package/generated/v1/schemas/statusdeliveries.list.response.json +82 -0
  63. package/generated/v1/snippets/projectnotifications.read.json +6 -0
  64. package/generated/v1/snippets/projectnotifications.rotateSigningKey.json +6 -0
  65. package/generated/v1/snippets/projectnotifications.update.json +6 -0
  66. package/generated/v1/snippets/statusdeliveries.list.json +6 -0
  67. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { effectiveCustomerLimitsSchema } from "./effective-limits.js";
2
2
  import { z } from "./zod.js";
3
3
  import { MEMBER_OPERATIONS } from "./members.js";
4
+ import { PROJECT_NOTIFICATION_OPERATIONS } from "./project-notifications.js";
4
5
  import { DATA_EXPORT_OPERATIONS } from "./data-export.js";
5
6
  import { ORGANIZATION_LIFECYCLE_OPERATIONS } from "./organization-lifecycle.js";
6
7
  import { API_UNUSED_RESPONSE_SCHEMA } from "./operation-definitions.js";
@@ -527,6 +528,7 @@ export const OPERATIONS = [
527
528
  },
528
529
  ...DATA_EXPORT_OPERATIONS,
529
530
  ...MEMBER_OPERATIONS,
531
+ ...PROJECT_NOTIFICATION_OPERATIONS,
530
532
  ...ORGANIZATION_LIFECYCLE_OPERATIONS,
531
533
  {
532
534
  creates: false,
@@ -2492,7 +2494,7 @@ export const OPERATIONS = [
2492
2494
  creates: true,
2493
2495
  description: globalThis.GREATWAIT_RUNTIME_CONTRACTS_ONLY
2494
2496
  ? ""
2495
- : "Confirms one exact manual execution-credit quote and creates or replays its durable payment operation. Billing-owner authority and explicit agent approval apply; the Idempotency-Key preserves one payment identity across retries. Manual funding stays outside the automatic-charge ceiling. A browser redirect never grants credit: only authenticated provider reconciliation can move the operation to paid and grant its exact execution credit once, while the operation reports provider-confirmed tax and gross when known.",
2497
+ : "Confirms one exact manual execution-credit quote and creates or replays its durable payment operation. Billing-owner authority and explicit agent approval apply; the Idempotency-Key preserves one payment identity across retries. Manual funding stays outside the automatic-charge ceiling. A browser redirect never grants credit: only authenticated provider reconciliation can move the operation to paid and grant its exact execution credit once, while the operation reports provider-confirmed tax and gross when known. With savePaymentMethod, the payment method used becomes the organization's saved payment method once the payment is confirmed, unless one is already saved.",
2496
2498
  environments: ["live"],
2497
2499
  id: "billing.purchase",
2498
2500
  idempotent: true,
package/dist/policy.d.ts CHANGED
@@ -47,10 +47,11 @@ export declare function grantableScopes(): readonly Scope[];
47
47
  * that will be refused `authentication_required` on the only route it names,
48
48
  * for ever, and nothing about the key says so.
49
49
  *
50
- * `projects:read` remains excluded because enumerating an organization is a
51
- * signed-in member's question. Project writes are different: a key's authority
52
- * already names exactly the project that rename/archive/delete may affect, so
53
- * those scopes become usable when their operations do.
50
+ * Listing an organization's projects stays a signed-in member's question, and
51
+ * that operation refuses a key. `projects:read` is usable by a key all the same
52
+ * since W9-54, because reading its own project's notification settings declares
53
+ * it. A key's authority already names exactly the one project those reads,
54
+ * and rename/archive/delete, may affect.
54
55
  */
55
56
  export declare function credentialScopes(): readonly Scope[];
56
57
  /** One row of the generated policy matrix. */
package/dist/policy.js CHANGED
@@ -136,10 +136,11 @@ export function grantableScopes() {
136
136
  * that will be refused `authentication_required` on the only route it names,
137
137
  * for ever, and nothing about the key says so.
138
138
  *
139
- * `projects:read` remains excluded because enumerating an organization is a
140
- * signed-in member's question. Project writes are different: a key's authority
141
- * already names exactly the project that rename/archive/delete may affect, so
142
- * those scopes become usable when their operations do.
139
+ * Listing an organization's projects stays a signed-in member's question, and
140
+ * that operation refuses a key. `projects:read` is usable by a key all the same
141
+ * since W9-54, because reading its own project's notification settings declares
142
+ * it. A key's authority already names exactly the one project those reads,
143
+ * and rename/archive/delete, may affect.
143
144
  */
144
145
  export function credentialScopes() {
145
146
  const usable = new Set(allOperations()
@@ -0,0 +1,238 @@
1
+ import { z } from "./zod.js";
2
+ /** Per-project/environment preferences. Billing-safety notices are separate. */
3
+ export declare const notificationEmailRecipientsSchema: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
4
+ kind: import("zod").ZodLiteral<"admins">;
5
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
6
+ kind: import("zod").ZodLiteral<"members">;
7
+ memberIds: import("zod").ZodArray<import("zod").ZodString>;
8
+ }, import("zod/v4/core").$strict>], "kind">;
9
+ export declare const notificationEmailSettingsSchema: import("zod").ZodObject<{
10
+ enabled: import("zod").ZodBoolean;
11
+ recipients: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
12
+ kind: import("zod").ZodLiteral<"admins">;
13
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
14
+ kind: import("zod").ZodLiteral<"members">;
15
+ memberIds: import("zod").ZodArray<import("zod").ZodString>;
16
+ }, import("zod/v4/core").$strict>], "kind">;
17
+ scheduleKinds: import("zod").ZodEnum<{
18
+ both: "both";
19
+ "one-shot": "one-shot";
20
+ recurring: "recurring";
21
+ }>;
22
+ }, import("zod/v4/core").$strict>;
23
+ export declare const statusWebhookEventSchema: import("zod").ZodEnum<{
24
+ failed: "failed";
25
+ }>;
26
+ export type StatusWebhookEvent = z.infer<typeof statusWebhookEventSchema>;
27
+ export declare const statusWebhookConfigurationSchema: import("zod").ZodObject<{
28
+ url: import("zod").ZodString;
29
+ events: import("zod").ZodArray<import("zod").ZodEnum<{
30
+ failed: "failed";
31
+ }>>;
32
+ }, import("zod/v4/core").$strict>;
33
+ export declare const projectNotificationSettingsSchema: import("zod").ZodObject<{
34
+ project: import("zod").ZodString;
35
+ environmentKind: import("zod").ZodEnum<{
36
+ test: "test";
37
+ live: "live";
38
+ }>;
39
+ revision: import("zod").ZodNumber;
40
+ email: import("zod").ZodObject<{
41
+ enabled: import("zod").ZodBoolean;
42
+ recipients: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
43
+ kind: import("zod").ZodLiteral<"admins">;
44
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
45
+ kind: import("zod").ZodLiteral<"members">;
46
+ memberIds: import("zod").ZodArray<import("zod").ZodString>;
47
+ }, import("zod/v4/core").$strict>], "kind">;
48
+ scheduleKinds: import("zod").ZodEnum<{
49
+ both: "both";
50
+ "one-shot": "one-shot";
51
+ recurring: "recurring";
52
+ }>;
53
+ }, import("zod/v4/core").$strict>;
54
+ statusWebhook: import("zod").ZodOptional<import("zod").ZodObject<{
55
+ url: import("zod").ZodString;
56
+ events: import("zod").ZodArray<import("zod").ZodEnum<{
57
+ failed: "failed";
58
+ }>>;
59
+ signingKey: import("zod").ZodOptional<import("zod").ZodObject<{
60
+ id: import("zod").ZodString;
61
+ }, import("zod/v4/core").$strict>>;
62
+ revision: import("zod").ZodNumber;
63
+ }, import("zod/v4/core").$strict>>;
64
+ }, import("zod/v4/core").$strict>;
65
+ export type ProjectNotificationSettings = z.infer<typeof projectNotificationSettingsSchema>;
66
+ export declare const projectNotificationSettingsUpdateRequestSchema: import("zod").ZodObject<{
67
+ expectedRevision: import("zod").ZodNumber;
68
+ email: import("zod").ZodOptional<import("zod").ZodObject<{
69
+ enabled: import("zod").ZodBoolean;
70
+ recipients: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
71
+ kind: import("zod").ZodLiteral<"admins">;
72
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
73
+ kind: import("zod").ZodLiteral<"members">;
74
+ memberIds: import("zod").ZodArray<import("zod").ZodString>;
75
+ }, import("zod/v4/core").$strict>], "kind">;
76
+ scheduleKinds: import("zod").ZodEnum<{
77
+ both: "both";
78
+ "one-shot": "one-shot";
79
+ recurring: "recurring";
80
+ }>;
81
+ }, import("zod/v4/core").$strict>>;
82
+ statusWebhook: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodObject<{
83
+ url: import("zod").ZodString;
84
+ events: import("zod").ZodArray<import("zod").ZodEnum<{
85
+ failed: "failed";
86
+ }>>;
87
+ }, import("zod/v4/core").$strict>>>;
88
+ }, import("zod/v4/core").$strict>;
89
+ export type ProjectNotificationSettingsUpdateRequest = z.infer<typeof projectNotificationSettingsUpdateRequestSchema>;
90
+ export declare const statusSigningKeyRequestSchema: import("zod").ZodObject<{
91
+ expectedRevision: import("zod").ZodNumber;
92
+ }, import("zod/v4/core").$strict>;
93
+ export declare const statusSigningKeyCreatedSchema: import("zod").ZodObject<{
94
+ settings: import("zod").ZodObject<{
95
+ project: import("zod").ZodString;
96
+ environmentKind: import("zod").ZodEnum<{
97
+ test: "test";
98
+ live: "live";
99
+ }>;
100
+ revision: import("zod").ZodNumber;
101
+ email: import("zod").ZodObject<{
102
+ enabled: import("zod").ZodBoolean;
103
+ recipients: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
104
+ kind: import("zod").ZodLiteral<"admins">;
105
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
106
+ kind: import("zod").ZodLiteral<"members">;
107
+ memberIds: import("zod").ZodArray<import("zod").ZodString>;
108
+ }, import("zod/v4/core").$strict>], "kind">;
109
+ scheduleKinds: import("zod").ZodEnum<{
110
+ both: "both";
111
+ "one-shot": "one-shot";
112
+ recurring: "recurring";
113
+ }>;
114
+ }, import("zod/v4/core").$strict>;
115
+ statusWebhook: import("zod").ZodOptional<import("zod").ZodObject<{
116
+ url: import("zod").ZodString;
117
+ events: import("zod").ZodArray<import("zod").ZodEnum<{
118
+ failed: "failed";
119
+ }>>;
120
+ signingKey: import("zod").ZodOptional<import("zod").ZodObject<{
121
+ id: import("zod").ZodString;
122
+ }, import("zod/v4/core").$strict>>;
123
+ revision: import("zod").ZodNumber;
124
+ }, import("zod/v4/core").$strict>>;
125
+ }, import("zod/v4/core").$strict>;
126
+ keyId: import("zod").ZodString;
127
+ secret: import("zod").ZodString;
128
+ shownOnce: import("zod").ZodLiteral<true>;
129
+ }, import("zod/v4/core").$strict>;
130
+ export type StatusSigningKeyCreated = z.infer<typeof statusSigningKeyCreatedSchema>;
131
+ /** Safe notification payload: no customer request or response content. */
132
+ export declare const statusWebhookPayloadSchema: import("zod").ZodObject<{
133
+ version: import("zod").ZodLiteral<"2026-10-08">;
134
+ eventId: import("zod").ZodString;
135
+ type: import("zod").ZodEnum<{
136
+ failed: "failed";
137
+ }>;
138
+ projectId: import("zod").ZodString;
139
+ environmentKind: import("zod").ZodEnum<{
140
+ test: "test";
141
+ live: "live";
142
+ }>;
143
+ scheduleId: import("zod").ZodString;
144
+ occurrenceId: import("zod").ZodString;
145
+ occurredAt: import("zod").ZodString;
146
+ outcomeOrigin: import("zod").ZodEnum<{
147
+ customer: "customer";
148
+ platform: "platform";
149
+ }>;
150
+ diagnostic: import("zod").ZodOptional<import("zod").ZodString>;
151
+ statusCode: import("zod").ZodOptional<import("zod").ZodNumber>;
152
+ pause: import("zod").ZodOptional<import("zod").ZodUnknown>;
153
+ }, import("zod/v4/core").$strip>;
154
+ export type StatusWebhookPayload = z.infer<typeof statusWebhookPayloadSchema>;
155
+ export declare const statusWebhookDeliverySchema: import("zod").ZodObject<{
156
+ id: import("zod").ZodString;
157
+ event: import("zod").ZodEnum<{
158
+ failed: "failed";
159
+ }>;
160
+ schedule: import("zod").ZodString;
161
+ occurrence: import("zod").ZodString;
162
+ occurredAt: import("zod").ZodString;
163
+ url: import("zod").ZodString;
164
+ state: import("zod").ZodEnum<{
165
+ suppressed: "suppressed";
166
+ failed: "failed";
167
+ pending: "pending";
168
+ delivered: "delivered";
169
+ delivering: "delivering";
170
+ }>;
171
+ attempts: import("zod").ZodNumber;
172
+ nextAttemptAt: import("zod").ZodOptional<import("zod").ZodString>;
173
+ lastStatus: import("zod").ZodOptional<import("zod").ZodNumber>;
174
+ lastError: import("zod").ZodOptional<import("zod").ZodString>;
175
+ }, import("zod/v4/core").$strict>;
176
+ export type StatusWebhookDelivery = z.infer<typeof statusWebhookDeliverySchema>;
177
+ export declare const statusWebhookDeliveryPageSchema: import("zod").ZodObject<{
178
+ data: import("zod").ZodArray<import("zod").ZodObject<{
179
+ id: import("zod").ZodString;
180
+ event: import("zod").ZodEnum<{
181
+ failed: "failed";
182
+ }>;
183
+ schedule: import("zod").ZodString;
184
+ occurrence: import("zod").ZodString;
185
+ occurredAt: import("zod").ZodString;
186
+ url: import("zod").ZodString;
187
+ state: import("zod").ZodEnum<{
188
+ suppressed: "suppressed";
189
+ failed: "failed";
190
+ pending: "pending";
191
+ delivered: "delivered";
192
+ delivering: "delivering";
193
+ }>;
194
+ attempts: import("zod").ZodNumber;
195
+ nextAttemptAt: import("zod").ZodOptional<import("zod").ZodString>;
196
+ lastStatus: import("zod").ZodOptional<import("zod").ZodNumber>;
197
+ lastError: import("zod").ZodOptional<import("zod").ZodString>;
198
+ }, import("zod/v4/core").$strict>>;
199
+ nextCursor: import("zod").ZodOptional<import("zod").ZodString>;
200
+ }, import("zod/v4/core").$strict>;
201
+ export type StatusWebhookDeliveryPage = z.infer<typeof statusWebhookDeliveryPageSchema>;
202
+ export declare const PROJECT_NOTIFICATION_OPERATIONS: readonly [import("./operations.js").OperationDefinition & {
203
+ readonly id: "projectnotifications.read";
204
+ }, import("./operations.js").OperationDefinition & {
205
+ readonly id: "projectnotifications.update";
206
+ } & {
207
+ readonly request: import("zod").ZodObject<{
208
+ expectedRevision: import("zod").ZodNumber;
209
+ email: import("zod").ZodOptional<import("zod").ZodObject<{
210
+ enabled: import("zod").ZodBoolean;
211
+ recipients: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
212
+ kind: import("zod").ZodLiteral<"admins">;
213
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
214
+ kind: import("zod").ZodLiteral<"members">;
215
+ memberIds: import("zod").ZodArray<import("zod").ZodString>;
216
+ }, import("zod/v4/core").$strict>], "kind">;
217
+ scheduleKinds: import("zod").ZodEnum<{
218
+ both: "both";
219
+ "one-shot": "one-shot";
220
+ recurring: "recurring";
221
+ }>;
222
+ }, import("zod/v4/core").$strict>>;
223
+ statusWebhook: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodObject<{
224
+ url: import("zod").ZodString;
225
+ events: import("zod").ZodArray<import("zod").ZodEnum<{
226
+ failed: "failed";
227
+ }>>;
228
+ }, import("zod/v4/core").$strict>>>;
229
+ }, import("zod/v4/core").$strict>;
230
+ }, import("./operations.js").OperationDefinition & {
231
+ readonly id: "projectnotifications.rotateSigningKey";
232
+ } & {
233
+ readonly request: import("zod").ZodObject<{
234
+ expectedRevision: import("zod").ZodNumber;
235
+ }, import("zod/v4/core").$strict>;
236
+ }, import("./operations.js").OperationDefinition & {
237
+ readonly id: "statusdeliveries.list";
238
+ }];
@@ -0,0 +1,236 @@
1
+ import { z } from "./zod.js";
2
+ import { environmentKindSchema } from "./authority.js";
3
+ import { callbackSigningKeyIdSchema, occurrenceIdSchema, projectIdSchema, scheduleIdSchema, } from "./identifiers.js";
4
+ import { memberIdSchema } from "./members.js";
5
+ import { timestampSchema } from "./time.js";
6
+ import { pageRequestSchema, requiredIdempotencyRequestHeaderSchema, } from "./protocol.js";
7
+ import { API_UNUSED_RESPONSE_SCHEMA, defineOperations, } from "./operation-definitions.js";
8
+ /** Per-project/environment preferences. Billing-safety notices are separate. */
9
+ export const notificationEmailRecipientsSchema = z.discriminatedUnion("kind", [
10
+ z.strictObject({ kind: z.literal("admins") }),
11
+ z.strictObject({
12
+ kind: z.literal("members"),
13
+ memberIds: z
14
+ .array(memberIdSchema)
15
+ .min(1)
16
+ .max(100)
17
+ .refine((ids) => new Set(ids).size === ids.length, "members must be unique"),
18
+ }),
19
+ ]);
20
+ export const notificationEmailSettingsSchema = z.strictObject({
21
+ enabled: z.boolean(),
22
+ recipients: notificationEmailRecipientsSchema,
23
+ scheduleKinds: z.enum(["both", "one-shot", "recurring"]),
24
+ });
25
+ export const statusWebhookEventSchema = z.enum(["failed"]);
26
+ export const statusWebhookConfigurationSchema = z.strictObject({
27
+ url: z.string().url().max(2_048),
28
+ events: z
29
+ .array(statusWebhookEventSchema)
30
+ .min(1)
31
+ .max(1)
32
+ .refine((events) => new Set(events).size === events.length, "events must be unique"),
33
+ });
34
+ export const projectNotificationSettingsSchema = z.strictObject({
35
+ project: projectIdSchema,
36
+ environmentKind: environmentKindSchema,
37
+ revision: z.number().int().positive(),
38
+ email: notificationEmailSettingsSchema,
39
+ statusWebhook: statusWebhookConfigurationSchema
40
+ .extend({
41
+ signingKey: z.strictObject({ id: callbackSigningKeyIdSchema }).optional(),
42
+ revision: z.number().int().positive(),
43
+ })
44
+ .optional(),
45
+ });
46
+ export const projectNotificationSettingsUpdateRequestSchema = z
47
+ .strictObject({
48
+ expectedRevision: z.number().int().positive(),
49
+ email: notificationEmailSettingsSchema.optional(),
50
+ statusWebhook: statusWebhookConfigurationSchema.nullable().optional(),
51
+ })
52
+ .refine((request) => request.email !== undefined || request.statusWebhook !== undefined, "choose settings to change");
53
+ export const statusSigningKeyRequestSchema = z.strictObject({
54
+ expectedRevision: z.number().int().positive(),
55
+ });
56
+ export const statusSigningKeyCreatedSchema = z.strictObject({
57
+ settings: projectNotificationSettingsSchema,
58
+ keyId: callbackSigningKeyIdSchema,
59
+ secret: z.string().min(1),
60
+ shownOnce: z.literal(true),
61
+ });
62
+ /** Safe notification payload: no customer request or response content. */
63
+ export const statusWebhookPayloadSchema = z.object({
64
+ version: z.literal("2026-10-08"),
65
+ eventId: z.string().min(1).max(255),
66
+ type: statusWebhookEventSchema,
67
+ projectId: projectIdSchema,
68
+ environmentKind: environmentKindSchema,
69
+ scheduleId: scheduleIdSchema,
70
+ occurrenceId: occurrenceIdSchema,
71
+ occurredAt: timestampSchema,
72
+ outcomeOrigin: z.enum(["platform", "customer"]),
73
+ diagnostic: z.string().max(512).optional(),
74
+ statusCode: z.number().int().min(100).max(599).optional(),
75
+ pause: z.unknown().optional(),
76
+ });
77
+ export const statusWebhookDeliverySchema = z.strictObject({
78
+ id: z.string().min(1).max(255),
79
+ event: statusWebhookEventSchema,
80
+ schedule: scheduleIdSchema,
81
+ occurrence: occurrenceIdSchema,
82
+ occurredAt: timestampSchema,
83
+ url: z.string().url(),
84
+ state: z.enum(["pending", "delivering", "delivered", "failed", "suppressed"]),
85
+ attempts: z.number().int().nonnegative(),
86
+ nextAttemptAt: timestampSchema.optional(),
87
+ lastStatus: z.number().int().min(100).max(599).optional(),
88
+ lastError: z.string().max(128).optional(),
89
+ });
90
+ export const statusWebhookDeliveryPageSchema = z.strictObject({
91
+ data: z.array(statusWebhookDeliverySchema),
92
+ nextCursor: z.string().min(1).optional(),
93
+ });
94
+ const globals = globalThis;
95
+ const settings = {
96
+ project: "proj_01h8xyz9k2m4n6p8r0t2v4w6y8",
97
+ environmentKind: "live",
98
+ revision: 1,
99
+ email: {
100
+ enabled: true,
101
+ recipients: { kind: "admins" },
102
+ scheduleKinds: "both",
103
+ },
104
+ };
105
+ const common = {
106
+ creates: false,
107
+ principals: ["api-credential", "oauth", "session"],
108
+ sessionAuthority: "headers",
109
+ surfaces: ["api", "mock"],
110
+ problems: ["invalid_request", "not_found", "service_unavailable"],
111
+ };
112
+ export const PROJECT_NOTIFICATION_OPERATIONS = defineOperations([
113
+ {
114
+ ...common,
115
+ id: "projectnotifications.read",
116
+ method: "GET",
117
+ path: "/v1/projects/{projectId}/notification-settings",
118
+ idempotent: true,
119
+ mutates: false,
120
+ mcp: { kind: "tool", destructive: false, openWorld: false },
121
+ scopes: ["projects:read"],
122
+ response: globals.GREATWAIT_API_REQUEST_REGISTRY
123
+ ? API_UNUSED_RESPONSE_SCHEMA
124
+ : projectNotificationSettingsSchema,
125
+ example: globals.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES ? {} : settings,
126
+ summary: globals.GREATWAIT_API_REQUEST_REGISTRY
127
+ ? ""
128
+ : "Read delivery notification settings",
129
+ description: globals.GREATWAIT_RUNTIME_CONTRACTS_ONLY
130
+ ? ""
131
+ : "Read the verified project and environment's email failure alerts and failure webhook preferences. Defaults are email on to current organization admins and both one-shot and recurring schedules. Every terminal failed occurrence creates a separate email for each eligible recipient. Signing secrets are absent. Manual redelivery does not repeat occurrence lifecycle events.",
132
+ },
133
+ {
134
+ ...common,
135
+ id: "projectnotifications.update",
136
+ method: "PATCH",
137
+ path: "/v1/projects/{projectId}/notification-settings",
138
+ idempotent: true,
139
+ mutates: true,
140
+ mcp: { kind: "tool", destructive: false, openWorld: true },
141
+ scopes: ["projects:administer"],
142
+ problems: [
143
+ ...common.problems,
144
+ "revision_conflict",
145
+ "idempotency_key_reused",
146
+ "rate_limited",
147
+ ],
148
+ requestHeaders: requiredIdempotencyRequestHeaderSchema,
149
+ request: projectNotificationSettingsUpdateRequestSchema,
150
+ requestExample: globals.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES
151
+ ? {}
152
+ : { expectedRevision: 1, email: settings.email },
153
+ response: globals.GREATWAIT_API_REQUEST_REGISTRY
154
+ ? API_UNUSED_RESPONSE_SCHEMA
155
+ : projectNotificationSettingsSchema,
156
+ example: globals.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES
157
+ ? {}
158
+ : { ...settings, revision: 2 },
159
+ summary: globals.GREATWAIT_API_REQUEST_REGISTRY
160
+ ? ""
161
+ : "Update delivery notification settings",
162
+ description: globals.GREATWAIT_RUNTIME_CONTRACTS_ONLY
163
+ ? ""
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. Null disables the status webhook. Changing URL or filters never reveals a signing secret. Mint the first key through the secure signing-key operation before webhook delivery starts. 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
+ },
166
+ {
167
+ ...common,
168
+ id: "projectnotifications.rotateSigningKey",
169
+ method: "POST",
170
+ path: "/v1/projects/{projectId}/notification-settings/status-signing-key",
171
+ idempotent: false,
172
+ mutates: true,
173
+ mcp: {
174
+ kind: "unavailable",
175
+ reason: "Minting or rotating returns a one-time signing secret. MCP has no negotiated secure-result channel that keeps it out of ordinary tool history. Configure preferences with projectnotifications_update, then use the dashboard or an authenticated REST/SDK/CLI client for the secret.",
176
+ },
177
+ scopes: ["projects:administer"],
178
+ problems: [
179
+ ...common.problems,
180
+ "revision_conflict",
181
+ "state_conflict",
182
+ "capability_not_configured",
183
+ ],
184
+ request: statusSigningKeyRequestSchema,
185
+ requestExample: globals.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES
186
+ ? {}
187
+ : { expectedRevision: 1 },
188
+ response: globals.GREATWAIT_API_REQUEST_REGISTRY
189
+ ? API_UNUSED_RESPONSE_SCHEMA
190
+ : statusSigningKeyCreatedSchema,
191
+ example: globals.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES
192
+ ? {}
193
+ : {
194
+ settings: {
195
+ ...settings,
196
+ revision: 2,
197
+ statusWebhook: {
198
+ url: "https://hooks.example.com/status",
199
+ events: ["failed"],
200
+ revision: 2,
201
+ signingKey: { id: "csk_01h8xyz9k2m4n6p8r0t2v4w6y8" },
202
+ },
203
+ },
204
+ keyId: "csk_01h8xyz9k2m4n6p8r0t2v4w6y8",
205
+ secret: "ptsk_live_<the-one-time-status-secret>",
206
+ shownOnce: true,
207
+ },
208
+ summary: globals.GREATWAIT_API_REQUEST_REGISTRY
209
+ ? ""
210
+ : "Mint or rotate the status webhook signing key",
211
+ description: globals.GREATWAIT_RUNTIME_CONTRACTS_ONLY
212
+ ? ""
213
+ : "An admin mints the first key or replaces the current key for an already configured status webhook at an expected revision. The secret appears only in this successful response and cannot be read back. A lost response requires a fresh revision read and another rotation. Queued deliveries using the replaced signing key are suppressed. The request is not automatically replayable; stale retries are refused. The signature covers the exact emitted body bytes.",
214
+ },
215
+ {
216
+ ...common,
217
+ id: "statusdeliveries.list",
218
+ method: "GET",
219
+ path: "/v1/projects/{projectId}/status-deliveries",
220
+ idempotent: true,
221
+ mutates: false,
222
+ mcp: { kind: "tool", destructive: false, openWorld: false },
223
+ scopes: ["occurrences:read"],
224
+ query: pageRequestSchema,
225
+ response: globals.GREATWAIT_API_REQUEST_REGISTRY
226
+ ? API_UNUSED_RESPONSE_SCHEMA
227
+ : statusWebhookDeliveryPageSchema,
228
+ example: globals.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES ? {} : { data: [] },
229
+ summary: globals.GREATWAIT_API_REQUEST_REGISTRY
230
+ ? ""
231
+ : "List failure webhook deliveries",
232
+ description: globals.GREATWAIT_RUNTIME_CONTRACTS_ONLY
233
+ ? ""
234
+ : "Read the verified project and environment's failure delivery trail, including retry state and actual outbound calls. Failed events and every retry are free. Status delivery failures never create another notification or change the customer's schedule outcome. Customer callback contents and signing secrets are absent.",
235
+ },
236
+ ]);