@greatwait/contracts 0.2.3 → 0.3.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.
Files changed (90) hide show
  1. package/dist/attempt-search.d.ts +235 -0
  2. package/dist/attempt-search.js +101 -0
  3. package/dist/authority.js +9 -9
  4. package/dist/billing.d.ts +4 -4
  5. package/dist/bulk-operations.d.ts +1832 -0
  6. package/dist/bulk-operations.js +610 -0
  7. package/dist/configuration-bounds.d.ts +12 -0
  8. package/dist/configuration-bounds.js +12 -0
  9. package/dist/configuration.d.ts +75 -0
  10. package/dist/configuration.js +242 -0
  11. package/dist/data-export.d.ts +3 -3
  12. package/dist/delivery.d.ts +1 -0
  13. package/dist/delivery.js +1 -0
  14. package/dist/effective-limits.d.ts +4 -4
  15. package/dist/endpoints.js +25 -25
  16. package/dist/execution-selection.d.ts +48 -0
  17. package/dist/execution-selection.js +21 -0
  18. package/dist/http-request.d.ts +1 -1
  19. package/dist/http-request.js +25 -23
  20. package/dist/identifiers.d.ts +2 -0
  21. package/dist/identifiers.js +21 -19
  22. package/dist/identity.d.ts +3 -3
  23. package/dist/index.d.ts +5 -0
  24. package/dist/index.js +5 -0
  25. package/dist/occurrence-states.d.ts +14 -0
  26. package/dist/occurrence-states.js +13 -0
  27. package/dist/operational-config.js +7 -6
  28. package/dist/operations.d.ts +573 -89
  29. package/dist/operations.js +67 -0
  30. package/dist/protocol.d.ts +19 -5
  31. package/dist/protocol.js +47 -40
  32. package/dist/schedule-selection.d.ts +28 -0
  33. package/dist/schedule-selection.js +48 -0
  34. package/dist/scheduling-records.d.ts +20 -20
  35. package/dist/scheduling.d.ts +109 -63
  36. package/dist/scheduling.js +101 -117
  37. package/dist/signatures.d.ts +6 -6
  38. package/dist/signatures.js +24 -24
  39. package/dist/stored-http.d.ts +18 -0
  40. package/dist/stored-http.js +106 -0
  41. package/dist/test-sink.d.ts +6 -6
  42. package/dist/time.js +7 -7
  43. package/dist/usage.d.ts +3 -3
  44. package/generated/v1/examples/attempts.search.response.json +42 -0
  45. package/generated/v1/examples/bulk.cancel.request.json +3 -0
  46. package/generated/v1/examples/bulk.cancel.response.json +59 -0
  47. package/generated/v1/examples/bulk.confirm.request.json +5 -0
  48. package/generated/v1/examples/bulk.confirm.response.json +59 -0
  49. package/generated/v1/examples/bulk.items.response.json +3 -0
  50. package/generated/v1/examples/bulk.list.response.json +63 -0
  51. package/generated/v1/examples/bulk.pause.request.json +3 -0
  52. package/generated/v1/examples/bulk.pause.response.json +59 -0
  53. package/generated/v1/examples/bulk.preview.request.json +12 -0
  54. package/generated/v1/examples/bulk.preview.response.json +59 -0
  55. package/generated/v1/examples/bulk.read.response.json +59 -0
  56. package/generated/v1/examples/bulk.resume.request.json +3 -0
  57. package/generated/v1/examples/bulk.resume.response.json +59 -0
  58. package/generated/v1/manifest.json +243 -1
  59. package/generated/v1/openapi.json +21569 -2418
  60. package/generated/v1/policy-matrix.json +63 -0
  61. package/generated/v1/schemas/attempts.search.query.json +96 -0
  62. package/generated/v1/schemas/attempts.search.response.json +271 -0
  63. package/generated/v1/schemas/bulk.cancel.request.json +13 -0
  64. package/generated/v1/schemas/bulk.cancel.response.json +1717 -0
  65. package/generated/v1/schemas/bulk.confirm.request-headers.json +13 -0
  66. package/generated/v1/schemas/bulk.confirm.request.json +19 -0
  67. package/generated/v1/schemas/bulk.confirm.response.json +1717 -0
  68. package/generated/v1/schemas/bulk.items.query.json +29 -0
  69. package/generated/v1/schemas/bulk.items.response.json +194 -0
  70. package/generated/v1/schemas/bulk.list.query.json +32 -0
  71. package/generated/v1/schemas/bulk.list.response.json +1789 -0
  72. package/generated/v1/schemas/bulk.pause.request.json +13 -0
  73. package/generated/v1/schemas/bulk.pause.response.json +1717 -0
  74. package/generated/v1/schemas/bulk.preview.request.json +1218 -0
  75. package/generated/v1/schemas/bulk.preview.response.json +1717 -0
  76. package/generated/v1/schemas/bulk.read.response.json +1717 -0
  77. package/generated/v1/schemas/bulk.resume.request.json +13 -0
  78. package/generated/v1/schemas/bulk.resume.response.json +1717 -0
  79. package/generated/v1/schemas/executions.list.query.json +33 -12
  80. package/generated/v1/schemas/schedules.list.query.json +32 -3
  81. package/generated/v1/snippets/attempts.search.json +6 -0
  82. package/generated/v1/snippets/bulk.cancel.json +6 -0
  83. package/generated/v1/snippets/bulk.confirm.json +6 -0
  84. package/generated/v1/snippets/bulk.items.json +6 -0
  85. package/generated/v1/snippets/bulk.list.json +6 -0
  86. package/generated/v1/snippets/bulk.pause.json +6 -0
  87. package/generated/v1/snippets/bulk.preview.json +6 -0
  88. package/generated/v1/snippets/bulk.read.json +6 -0
  89. package/generated/v1/snippets/bulk.resume.json +6 -0
  90. package/package.json +1 -1
@@ -0,0 +1,610 @@
1
+ import { nonnegativeMicrodollarAmountSchema, BILLING_ACTIVATION_MODES, } from "./billing.js";
2
+ import { z } from "./zod.js";
3
+ import { authoritySchema } from "./authority.js";
4
+ import { bulkJobIdSchema, scheduleIdSchema, occurrenceIdSchema, attemptIdSchema, } from "./identifiers.js";
5
+ import { scheduleSelectionSchema, normalizeScheduleSelection, } from "./schedule-selection.js";
6
+ import { executionSelectionSchema, normalizeExecutionSelection, } from "./execution-selection.js";
7
+ import { timestampSchema, timeZoneSchema } from "./time.js";
8
+ import { latenessPolicySchema, deliveryOverlapPolicySchema, } from "./scheduling.js";
9
+ import { BULK_CONFIGURATION_MAXIMA, FIXED_INTERVAL_MIN_SECONDS, FIXED_INTERVAL_MAX_SECONDS, } from "./configuration-bounds.js";
10
+ import { CONFIGURATION_DEFAULTS } from "./configuration.js";
11
+ import { pageRequestSchema, requiredIdempotencyRequestHeaderSchema, } from "./protocol.js";
12
+ import { defineOperations, API_UNUSED_RESPONSE_SCHEMA, } from "./operation-definitions.js";
13
+ export const BULK_OPERATIONS = [
14
+ "retry",
15
+ "cancel",
16
+ "reschedule",
17
+ "pause",
18
+ "resume",
19
+ ];
20
+ export const bulkOperationSchema = z.enum(BULK_OPERATIONS);
21
+ export const bulkTargetSchema = z.enum([
22
+ "schedules",
23
+ "parent_schedules",
24
+ "occurrences",
25
+ ]);
26
+ /** The action registry owns targets, permissions and one canonical effect path. */
27
+ export const BULK_OPERATION_REGISTRY = Object.freeze({
28
+ retry: {
29
+ targets: ["occurrences"],
30
+ scopes: ["occurrences:read", "occurrences:redeliver"],
31
+ effect: "occurrences.redeliver",
32
+ duplicateEffectAcknowledgment: true,
33
+ },
34
+ cancel: {
35
+ targets: ["schedules", "parent_schedules"],
36
+ scopes: ["schedules:read", "schedules:write"],
37
+ effect: "schedules.cancel",
38
+ duplicateEffectAcknowledgment: false,
39
+ },
40
+ reschedule: {
41
+ targets: ["schedules", "parent_schedules"],
42
+ scopes: ["schedules:read", "schedules:write"],
43
+ effect: "schedules.replace",
44
+ duplicateEffectAcknowledgment: false,
45
+ },
46
+ pause: {
47
+ targets: ["schedules", "parent_schedules"],
48
+ scopes: ["schedules:read", "schedules:write"],
49
+ effect: "schedules.pause",
50
+ duplicateEffectAcknowledgment: false,
51
+ },
52
+ resume: {
53
+ targets: ["schedules", "parent_schedules"],
54
+ scopes: ["schedules:read", "schedules:write"],
55
+ effect: "schedules.resume",
56
+ duplicateEffectAcknowledgment: false,
57
+ },
58
+ });
59
+ const scheduleFilter = scheduleSelectionSchema
60
+ .strict()
61
+ .refine((filter) => filter.dueAfter === undefined ||
62
+ filter.dueBefore === undefined ||
63
+ Date.parse(filter.dueAfter) < Date.parse(filter.dueBefore), { message: "dueBefore must be later than dueAfter", path: ["dueBefore"] });
64
+ const executionFilter = executionSelectionSchema
65
+ .strict()
66
+ .refine((filter) => filter.from === undefined ||
67
+ filter.to === undefined ||
68
+ Date.parse(filter.from) < Date.parse(filter.to), { message: "to must be later than from", path: ["to"] });
69
+ export const bulkSelectionSchema = z.union([
70
+ z
71
+ .object({
72
+ kind: z.literal("ids"),
73
+ resource: z.literal("schedules"),
74
+ ids: z
75
+ .array(scheduleIdSchema)
76
+ .max(BULK_CONFIGURATION_MAXIMA.bulkMaxTargets),
77
+ })
78
+ .strict(),
79
+ z
80
+ .object({
81
+ kind: z.literal("ids"),
82
+ resource: z.literal("executions"),
83
+ ids: z
84
+ .array(occurrenceIdSchema)
85
+ .max(BULK_CONFIGURATION_MAXIMA.bulkMaxTargets),
86
+ })
87
+ .strict(),
88
+ z
89
+ .object({
90
+ kind: z.literal("all_matching"),
91
+ resource: z.literal("schedules"),
92
+ filter: scheduleFilter,
93
+ })
94
+ .strict(),
95
+ z
96
+ .object({
97
+ kind: z.literal("all_matching"),
98
+ resource: z.literal("executions"),
99
+ filter: executionFilter,
100
+ })
101
+ .strict(),
102
+ ]);
103
+ export function normalizeBulkSelection(selection) {
104
+ if (selection.kind === "ids")
105
+ return { ...selection, ids: [...new Set(selection.ids)].sort() };
106
+ return selection.resource === "schedules"
107
+ ? { ...selection, filter: normalizeScheduleSelection(selection.filter) }
108
+ : { ...selection, filter: normalizeExecutionSelection(selection.filter) };
109
+ }
110
+ export const bulkRescheduleParametersSchema = z.discriminatedUnion("mode", [
111
+ z.object({ mode: z.literal("absolute"), at: timestampSchema }).strict(),
112
+ z
113
+ .object({
114
+ mode: z.literal("shift_existing"),
115
+ seconds: z
116
+ .number()
117
+ .int()
118
+ .min(-FIXED_INTERVAL_MAX_SECONDS)
119
+ .max(FIXED_INTERVAL_MAX_SECONDS)
120
+ .refine((seconds) => seconds !== 0, "shift must be nonzero"),
121
+ })
122
+ .strict(),
123
+ z
124
+ .object({
125
+ mode: z.literal("delay_from_reference"),
126
+ seconds: z.number().int().min(1).max(FIXED_INTERVAL_MAX_SECONDS),
127
+ })
128
+ .strict(),
129
+ z
130
+ .object({
131
+ mode: z.literal("definition"),
132
+ definition: z.union([
133
+ z
134
+ .object({
135
+ everySeconds: z
136
+ .number()
137
+ .int()
138
+ .min(FIXED_INTERVAL_MIN_SECONDS)
139
+ .max(FIXED_INTERVAL_MAX_SECONDS),
140
+ })
141
+ .strict(),
142
+ z
143
+ .object({
144
+ cron: z.string().min(1).max(256),
145
+ timeZone: timeZoneSchema,
146
+ })
147
+ .strict(),
148
+ ]),
149
+ })
150
+ .strict(),
151
+ ]);
152
+ const previewFields = {
153
+ target: bulkTargetSchema,
154
+ selection: bulkSelectionSchema,
155
+ };
156
+ export const bulkPreviewRequestSchema = z
157
+ .discriminatedUnion("operation", [
158
+ z
159
+ .object({
160
+ ...previewFields,
161
+ operation: z.literal("retry"),
162
+ parameters: z
163
+ .object({ includeSucceeded: z.boolean().optional() })
164
+ .strict(),
165
+ })
166
+ .strict(),
167
+ z
168
+ .object({
169
+ ...previewFields,
170
+ operation: z.literal("reschedule"),
171
+ parameters: bulkRescheduleParametersSchema,
172
+ })
173
+ .strict(),
174
+ ...["cancel", "pause", "resume"].map((operation) => z
175
+ .object({
176
+ ...previewFields,
177
+ operation: z.literal(operation),
178
+ parameters: z.object({}).strict(),
179
+ })
180
+ .strict()),
181
+ ])
182
+ .superRefine((request, context) => {
183
+ const registry = BULK_OPERATION_REGISTRY[request.operation];
184
+ if (!registry.targets.includes(request.target))
185
+ context.addIssue({
186
+ code: "custom",
187
+ path: ["target"],
188
+ message: "unsupported target for this operation",
189
+ });
190
+ if ((request.target === "schedules" &&
191
+ request.selection.resource !== "schedules") ||
192
+ (request.target === "parent_schedules" &&
193
+ request.selection.resource !== "executions") ||
194
+ (request.target === "occurrences" &&
195
+ request.selection.resource !== "executions"))
196
+ context.addIssue({
197
+ code: "custom",
198
+ path: ["selection", "resource"],
199
+ message: "resource does not match the explicitly chosen target",
200
+ });
201
+ if (request.operation === "resume" &&
202
+ request.selection.kind === "all_matching" &&
203
+ request.selection.filter.status !== undefined &&
204
+ request.selection.filter.status !== "paused")
205
+ context.addIssue({
206
+ code: "custom",
207
+ path: ["selection", "filter", "status"],
208
+ message: "bulk Resume candidates must be paused",
209
+ });
210
+ });
211
+ export const bulkConfirmRequestSchema = z
212
+ .object({
213
+ intentDigest: z.string().regex(/^[a-f0-9]{64}$/u),
214
+ confirmed: z.literal(true),
215
+ acknowledgeDuplicateEffects: z.boolean(),
216
+ })
217
+ .strict();
218
+ export const BULK_JOB_STATES = [
219
+ "preparing",
220
+ "awaiting_confirmation",
221
+ "queued",
222
+ "running",
223
+ "paused",
224
+ "blocked",
225
+ "completed",
226
+ "completed_with_failures",
227
+ "cancelled",
228
+ "expired",
229
+ "refused",
230
+ ];
231
+ export const bulkJobStateSchema = z.enum(BULK_JOB_STATES);
232
+ export const BULK_ITEM_STATES = [
233
+ "pending",
234
+ "running",
235
+ "succeeded",
236
+ "no_op",
237
+ "skipped",
238
+ "conflicted",
239
+ "failed",
240
+ "cancelled",
241
+ ];
242
+ export const bulkItemStateSchema = z.enum(BULK_ITEM_STATES);
243
+ export const BULK_REASON_CODES = [
244
+ "eligible",
245
+ "already_active",
246
+ "already_paused",
247
+ "already_cancelled",
248
+ "invalid_state",
249
+ "unsupported_target",
250
+ "expired_input",
251
+ "unauthorized",
252
+ "concurrently_changed",
253
+ "past_time",
254
+ "attempt_limit",
255
+ "operation_failed",
256
+ "transient_failure",
257
+ "selection_too_large",
258
+ "preparation_incomplete",
259
+ "preview_expired",
260
+ "job_expired",
261
+ "job_cancelled",
262
+ "quota_exceeded",
263
+ "spending_limit",
264
+ "in_flight",
265
+ ];
266
+ export const bulkReasonSchema = z.enum(BULK_REASON_CODES);
267
+ export const bulkCountsSchema = z.object({
268
+ matched: z.number().int().nonnegative(),
269
+ eligible: z.number().int().nonnegative(),
270
+ ineligible: z.number().int().nonnegative(),
271
+ pending: z.number().int().nonnegative(),
272
+ running: z.number().int().nonnegative(),
273
+ succeeded: z.number().int().nonnegative(),
274
+ noOp: z.number().int().nonnegative(),
275
+ skipped: z.number().int().nonnegative(),
276
+ conflicted: z.number().int().nonnegative(),
277
+ failed: z.number().int().nonnegative(),
278
+ cancelled: z.number().int().nonnegative(),
279
+ });
280
+ export const bulkReadbackSchema = z
281
+ .object({
282
+ status: z.string().optional(),
283
+ plannedFor: timestampSchema.optional(),
284
+ recurrence: z.string().optional(),
285
+ timeZone: z.string().optional(),
286
+ affectedFutureRuns: z.number().int().nonnegative().optional(),
287
+ latenessPolicy: latenessPolicySchema.optional(),
288
+ maxStalenessSeconds: z
289
+ .number()
290
+ .int()
291
+ .nonnegative()
292
+ .max(Number.MAX_SAFE_INTEGER)
293
+ .optional(),
294
+ overlapPolicy: deliveryOverlapPolicySchema.optional(),
295
+ nextRunNote: z.string().min(1).max(1_000).optional(),
296
+ })
297
+ .strict();
298
+ export const bulkItemSchema = z
299
+ .object({
300
+ id: z.string().min(1),
301
+ jobId: bulkJobIdSchema,
302
+ scheduleId: scheduleIdSchema,
303
+ occurrenceId: occurrenceIdSchema.optional(),
304
+ state: bulkItemStateSchema,
305
+ reason: bulkReasonSchema,
306
+ eligible: z.boolean(),
307
+ retryable: z.boolean(),
308
+ fence: z.string().min(1),
309
+ before: bulkReadbackSchema,
310
+ after: bulkReadbackSchema.optional(),
311
+ attemptId: attemptIdSchema.optional(),
312
+ actionId: z.string().min(1).optional(),
313
+ updatedAt: timestampSchema,
314
+ expiresAt: timestampSchema.optional(),
315
+ })
316
+ .strict();
317
+ export const bulkJobSchema = z
318
+ .object({
319
+ id: bulkJobIdSchema,
320
+ authority: authoritySchema,
321
+ intent: bulkPreviewRequestSchema,
322
+ state: bulkJobStateSchema,
323
+ version: z.number().int().positive(),
324
+ createdAt: timestampSchema,
325
+ updatedAt: timestampSchema,
326
+ referenceAt: timestampSchema,
327
+ preparationExpiresAt: timestampSchema,
328
+ previewExpiresAt: timestampSchema.optional(),
329
+ executionExpiresAt: timestampSchema.optional(),
330
+ resultsExpireAt: timestampSchema.optional(),
331
+ intentDigest: z
332
+ .string()
333
+ .regex(/^[a-f0-9]{64}$/u)
334
+ .optional(),
335
+ complete: z.boolean(),
336
+ counts: bulkCountsSchema,
337
+ reasons: z.array(z.object({
338
+ reason: bulkReasonSchema,
339
+ count: z.number().int().nonnegative(),
340
+ })),
341
+ warnings: z.array(z.string()),
342
+ samples: z.array(bulkItemSchema).max(10),
343
+ limits: z.object({
344
+ maxTargets: z.number().int().positive(),
345
+ executionLifetimeSeconds: z.number().int().positive(),
346
+ previewLifetimeSeconds: z.number().int().positive(),
347
+ resultRetentionSeconds: z.number().int().nonnegative(),
348
+ batchSize: z.number().int().positive(),
349
+ workerConcurrency: z.number().int().positive(),
350
+ }),
351
+ billing: z.object({
352
+ additionalAttemptsMinimum: z.number().int().nonnegative(),
353
+ additionalAttemptsMaximum: z.number().int().nonnegative().optional(),
354
+ currentLimits: z
355
+ .object({
356
+ capturedAt: timestampSchema,
357
+ billingMode: z.enum(BILLING_ACTIVATION_MODES),
358
+ attemptsPerOccurrence: z.number().int().positive(),
359
+ dailyAttemptQuota: z.literal("none"),
360
+ availableCreditMicrodollars: nonnegativeMicrodollarAmountSchema.optional(),
361
+ spendingCapMicrodollars: nonnegativeMicrodollarAmountSchema
362
+ .nullable()
363
+ .optional(),
364
+ remainingToSpendingCapMicrodollars: nonnegativeMicrodollarAmountSchema.optional(),
365
+ })
366
+ .strict()
367
+ .optional(),
368
+ exactChargeKnown: z.literal(false),
369
+ note: z.string(),
370
+ }),
371
+ reason: bulkReasonSchema.optional(),
372
+ })
373
+ .strict();
374
+ export const bulkJobPageSchema = z.object({
375
+ data: z.array(bulkJobSchema),
376
+ nextCursor: z.string().min(1).optional(),
377
+ });
378
+ export const bulkItemPageSchema = z.object({
379
+ data: z.array(bulkItemSchema),
380
+ nextCursor: z.string().min(1).optional(),
381
+ });
382
+ export const bulkListRequestSchema = pageRequestSchema.extend({
383
+ state: bulkJobStateSchema.optional(),
384
+ });
385
+ export const bulkItemListRequestSchema = pageRequestSchema.extend({
386
+ state: bulkItemStateSchema.optional(),
387
+ });
388
+ export const bulkControlRequestSchema = z
389
+ .object({ expectedVersion: z.number().int().positive() })
390
+ .strict();
391
+ const exampleIntent = {
392
+ operation: "pause",
393
+ target: "schedules",
394
+ selection: {
395
+ kind: "all_matching",
396
+ resource: "schedules",
397
+ filter: { tag: "reminders" },
398
+ },
399
+ parameters: {},
400
+ };
401
+ const exampleJob = {
402
+ id: "bjo_01h8xyz9k2m4n6p8r0t2v4w6y8",
403
+ authority: {
404
+ organization: "org_01h8xyz9k2m4n6p8r0t2v4w6y8",
405
+ project: "proj_01h8xyz9k2m4n6p8r0t2v4w6y8",
406
+ environment: "env_01h8xyz9k2m4n6p8r0t2v4w6y8",
407
+ environmentKind: "test",
408
+ },
409
+ intent: exampleIntent,
410
+ state: "awaiting_confirmation",
411
+ version: 1,
412
+ createdAt: "2035-06-01T00:00:00.000Z",
413
+ updatedAt: "2035-06-01T00:00:00.000Z",
414
+ referenceAt: "2035-06-01T00:00:00.000Z",
415
+ preparationExpiresAt: "2035-06-08T00:00:00.000Z",
416
+ previewExpiresAt: "2035-06-01T00:05:00.000Z",
417
+ intentDigest: "a".repeat(64),
418
+ complete: true,
419
+ counts: {
420
+ matched: 0,
421
+ eligible: 0,
422
+ ineligible: 0,
423
+ pending: 0,
424
+ running: 0,
425
+ succeeded: 0,
426
+ noOp: 0,
427
+ skipped: 0,
428
+ conflicted: 0,
429
+ failed: 0,
430
+ cancelled: 0,
431
+ },
432
+ reasons: [],
433
+ warnings: [],
434
+ samples: [],
435
+ limits: {
436
+ maxTargets: CONFIGURATION_DEFAULTS.bulkMaxTargets,
437
+ executionLifetimeSeconds: CONFIGURATION_DEFAULTS.bulkExecutionLifetimeSeconds,
438
+ previewLifetimeSeconds: CONFIGURATION_DEFAULTS.bulkPreviewLifetimeSeconds,
439
+ resultRetentionSeconds: CONFIGURATION_DEFAULTS.bulkResultRetentionSeconds,
440
+ batchSize: CONFIGURATION_DEFAULTS.bulkBatchSize,
441
+ workerConcurrency: CONFIGURATION_DEFAULTS.bulkWorkerConcurrency,
442
+ },
443
+ billing: {
444
+ additionalAttemptsMinimum: 0,
445
+ exactChargeKnown: false,
446
+ note: "Ordinary per-attempt billing and quota admission apply; preview creates no delivery or charge.",
447
+ },
448
+ };
449
+ const runtime = globalThis;
450
+ const requestOnly = runtime.GREATWAIT_API_REQUEST_REGISTRY;
451
+ const contractsOnly = runtime.GREATWAIT_RUNTIME_CONTRACTS_ONLY;
452
+ const withoutExamples = runtime.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES;
453
+ const shared = {
454
+ principals: ["api-credential", "oauth", "session"],
455
+ scopes: [],
456
+ sessionAuthority: "headers",
457
+ surfaces: ["api", "mock"],
458
+ problems: ["invalid_request", "not_found", "service_unavailable"],
459
+ mcp: { kind: "tool", destructive: false, openWorld: false },
460
+ };
461
+ /** Resolved action scopes from BULK_OPERATION_REGISTRY are mandatory on every endpoint. */
462
+ export const BULK_API_OPERATIONS = defineOperations([
463
+ {
464
+ ...shared,
465
+ id: "bulk.preview",
466
+ problems: [...shared.problems, "plan_limit_reached"],
467
+ method: "POST",
468
+ path: "/v1/bulk/jobs",
469
+ creates: true,
470
+ mutates: true,
471
+ idempotent: false,
472
+ summary: requestOnly ? "" : "Preview a bulk operation",
473
+ description: contractsOnly
474
+ ? ""
475
+ : "Prepares one bounded frozen selection for retry, cancel, reschedule, pause or resume. Requires the selected action's ordinary scopes and execution reads for parent mapping. Preview creates no deliveries, lifecycle mutations or billable attempts. Only complete awaiting_confirmation jobs may be confirmed.",
476
+ request: bulkPreviewRequestSchema,
477
+ requestExample: withoutExamples ? {} : exampleIntent,
478
+ response: runtime.GREATWAIT_API_REQUEST_REGISTRY
479
+ ? API_UNUSED_RESPONSE_SCHEMA
480
+ : bulkJobSchema,
481
+ example: runtime.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES ? {} : exampleJob,
482
+ },
483
+ {
484
+ ...shared,
485
+ id: "bulk.confirm",
486
+ problems: [
487
+ ...shared.problems,
488
+ "state_conflict",
489
+ "version_conflict",
490
+ "idempotency_key_reused",
491
+ "plan_limit_reached",
492
+ ],
493
+ method: "POST",
494
+ path: "/v1/bulk/jobs/{jobId}/confirm",
495
+ creates: false,
496
+ mutates: true,
497
+ idempotent: true,
498
+ mcp: { kind: "tool", destructive: true, openWorld: true },
499
+ summary: requestOnly ? "" : "Confirm an exact bulk preview",
500
+ description: contractsOnly
501
+ ? ""
502
+ : "Confirms the complete unexpired frozen target manifest by intent digest and explicit acknowledgment. Requires Idempotency-Key, the action's current scopes, and duplicate-effect acknowledgment for retry. Changed resources conflict; repeated identical submissions return the same job without applying work twice.",
503
+ request: bulkConfirmRequestSchema,
504
+ requestHeaders: requiredIdempotencyRequestHeaderSchema,
505
+ requestExample: withoutExamples
506
+ ? {}
507
+ : {
508
+ intentDigest: "a".repeat(64),
509
+ confirmed: true,
510
+ acknowledgeDuplicateEffects: false,
511
+ },
512
+ response: runtime.GREATWAIT_API_REQUEST_REGISTRY
513
+ ? API_UNUSED_RESPONSE_SCHEMA
514
+ : bulkJobSchema,
515
+ example: runtime.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES
516
+ ? {}
517
+ : { ...exampleJob, state: "queued" },
518
+ },
519
+ {
520
+ ...shared,
521
+ id: "bulk.read",
522
+ method: "GET",
523
+ path: "/v1/bulk/jobs/{jobId}",
524
+ creates: false,
525
+ mutates: false,
526
+ idempotent: true,
527
+ summary: requestOnly ? "" : "Read bulk preview or job progress",
528
+ description: contractsOnly
529
+ ? ""
530
+ : "Reads one scoped job, exact counts when preparation is complete, limits, warnings and reconciled durable outcomes. Requires the resolved action's current scopes; job records contain no callback payloads or secrets.",
531
+ response: runtime.GREATWAIT_API_REQUEST_REGISTRY
532
+ ? API_UNUSED_RESPONSE_SCHEMA
533
+ : bulkJobSchema,
534
+ example: runtime.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES ? {} : exampleJob,
535
+ },
536
+ {
537
+ ...shared,
538
+ id: "bulk.list",
539
+ method: "GET",
540
+ path: "/v1/bulk/jobs",
541
+ creates: false,
542
+ mutates: false,
543
+ idempotent: true,
544
+ summary: requestOnly ? "" : "List authorized bulk jobs",
545
+ description: contractsOnly
546
+ ? ""
547
+ : "Lists retained jobs in the current authority; only jobs whose action remains authorized are visible. Pagination is cursor based and bound to authority and state.",
548
+ query: bulkListRequestSchema,
549
+ response: runtime.GREATWAIT_API_REQUEST_REGISTRY
550
+ ? API_UNUSED_RESPONSE_SCHEMA
551
+ : bulkJobPageSchema,
552
+ example: runtime.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES
553
+ ? {}
554
+ : { data: [exampleJob] },
555
+ },
556
+ {
557
+ ...shared,
558
+ id: "bulk.items",
559
+ method: "GET",
560
+ path: "/v1/bulk/jobs/{jobId}/items",
561
+ creates: false,
562
+ mutates: false,
563
+ idempotent: true,
564
+ summary: requestOnly ? "" : "Inspect frozen bulk targets and results",
565
+ description: contractsOnly
566
+ ? ""
567
+ : "Pages through the frozen manifest and secret-safe item outcomes. Requires the resolved action's current scopes. Cursors bind this job and item-state filter; retained history cutoffs still apply.",
568
+ query: bulkItemListRequestSchema,
569
+ response: runtime.GREATWAIT_API_REQUEST_REGISTRY
570
+ ? API_UNUSED_RESPONSE_SCHEMA
571
+ : bulkItemPageSchema,
572
+ example: withoutExamples ? {} : { data: [] },
573
+ },
574
+ ...["pause", "resume", "cancel"].map((action) => ({
575
+ ...shared,
576
+ id: `bulk.${action}`,
577
+ problems: [
578
+ ...shared.problems,
579
+ "state_conflict",
580
+ "version_conflict",
581
+ ],
582
+ method: "POST",
583
+ path: `/v1/bulk/jobs/{jobId}/${action}`,
584
+ creates: false,
585
+ mutates: true,
586
+ idempotent: true,
587
+ mcp: { kind: "tool", destructive: true, openWorld: false },
588
+ summary: requestOnly
589
+ ? ""
590
+ : `${action[0].toUpperCase()}${action.slice(1)} a bulk job`,
591
+ description: contractsOnly
592
+ ? ""
593
+ : `Controls remaining bulk-job work with a mandatory expectedVersion fence and current resolved-action authorization. ${action === "resume" ? "Keeps the confirmed manifest and retries only eligible unfinished transient work." : "Already-started items may finish; completed callbacks and history remain."} This does not ${action} the selected schedules.`,
594
+ request: bulkControlRequestSchema,
595
+ requestExample: withoutExamples ? {} : { expectedVersion: 1 },
596
+ response: runtime.GREATWAIT_API_REQUEST_REGISTRY
597
+ ? API_UNUSED_RESPONSE_SCHEMA
598
+ : bulkJobSchema,
599
+ example: runtime.GREATWAIT_RUNTIME_WITHOUT_EXAMPLES
600
+ ? {}
601
+ : {
602
+ ...exampleJob,
603
+ state: action === "resume"
604
+ ? "queued"
605
+ : action === "pause"
606
+ ? "paused"
607
+ : "cancelled",
608
+ },
609
+ })),
610
+ ]);
@@ -11,3 +11,15 @@ export declare const PUBLIC_PAGE_SIZE: Readonly<{
11
11
  max: 100;
12
12
  min: 1;
13
13
  }>;
14
+ /** Transport/engineering envelopes; effective bulk policy is layered configuration. */
15
+ export declare const BULK_CONFIGURATION_MAXIMA: Readonly<{
16
+ bulkMaxTargets: 1000000;
17
+ bulkExecutionLifetimeSeconds: 31536000;
18
+ bulkPreviewLifetimeSeconds: 86400;
19
+ bulkResultRetentionSeconds: 31536000;
20
+ bulkBatchSize: 100;
21
+ bulkWorkerConcurrency: 25;
22
+ bulkActiveJobLimit: 25;
23
+ bulkWorkBudgetSeconds: 30;
24
+ bulkCarrierBatchSize: 1000;
25
+ }>;
@@ -11,3 +11,15 @@ export const PUBLIC_PAGE_SIZE = Object.freeze({
11
11
  max: 100,
12
12
  min: 1,
13
13
  });
14
+ /** Transport/engineering envelopes; effective bulk policy is layered configuration. */
15
+ export const BULK_CONFIGURATION_MAXIMA = Object.freeze({
16
+ bulkMaxTargets: 1_000_000,
17
+ bulkExecutionLifetimeSeconds: 31_536_000,
18
+ bulkPreviewLifetimeSeconds: 86_400,
19
+ bulkResultRetentionSeconds: 31_536_000,
20
+ bulkBatchSize: 100,
21
+ bulkWorkerConcurrency: 25,
22
+ bulkActiveJobLimit: 25,
23
+ bulkWorkBudgetSeconds: 30,
24
+ bulkCarrierBatchSize: 1_000,
25
+ });