@agentuity/schedule 3.0.10 → 3.1.0

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.
@@ -0,0 +1,717 @@
1
+ import { buildUrl, toServiceException } from '@agentuity/adapter';
2
+ import { z } from 'zod';
3
+ /**
4
+ * A scheduled job that fires at intervals defined by a cron expression.
5
+ *
6
+ * Schedules are the top-level resource. Each schedule has one or more
7
+ * {@link ScheduleDestination | destinations} that receive HTTP callbacks
8
+ * when the schedule fires.
9
+ */
10
+ export const ScheduleSchema = z.object({
11
+ /**
12
+ * Unique identifier for the schedule.
13
+ *
14
+ * @remarks Prefixed with `sch_`.
15
+ */
16
+ id: z.string().describe('Unique identifier for the schedule.'),
17
+ /**
18
+ * ISO 8601 timestamp when the schedule was created.
19
+ */
20
+ created_at: z.string().describe('ISO 8601 timestamp when the schedule was created.'),
21
+ /**
22
+ * ISO 8601 timestamp when the schedule was last modified.
23
+ */
24
+ updated_at: z.string().describe('ISO 8601 timestamp when the schedule was last modified.'),
25
+ /**
26
+ * ID of the user who created the schedule.
27
+ */
28
+ created_by: z.string().describe('ID of the user who created the schedule.'),
29
+ /**
30
+ * Human-readable name for the schedule.
31
+ */
32
+ name: z.string().describe('Human-readable name for the schedule.'),
33
+ /**
34
+ * Optional description of the schedule's purpose.
35
+ */
36
+ description: z.string().nullable().describe("Optional description of the schedule's purpose."),
37
+ /**
38
+ * A cron expression defining the schedule's firing interval
39
+ * (e.g., `'0 9 * * 1-5'` for weekdays at 9 AM).
40
+ *
41
+ * @remarks Validated on creation and update by the server.
42
+ * Supports standard five-field cron syntax including step values (e.g., every 5 minutes).
43
+ */
44
+ expression: z.string().describe("A cron expression defining the schedule's firing interval"),
45
+ /**
46
+ * ISO 8601 timestamp of the next scheduled execution.
47
+ *
48
+ * @remarks Automatically computed from the cron expression. Updated each time
49
+ * the schedule fires or the expression is changed.
50
+ */
51
+ due_date: z.string().describe('ISO 8601 timestamp of the next scheduled execution.'),
52
+ /**
53
+ * Whether this is a system-managed schedule.
54
+ *
55
+ * @remarks Internal schedules are created by the system and cannot be modified
56
+ * or deleted by users.
57
+ */
58
+ internal: z
59
+ .boolean()
60
+ .describe('Whether this is a system-managed schedule. Internal schedules cannot be modified or deleted users.'),
61
+ });
62
+ /**
63
+ * A delivery target for a scheduled job.
64
+ *
65
+ * When the schedule fires, an HTTP request is sent to each of its destinations.
66
+ */
67
+ export const ScheduleDestinationSchema = z.object({
68
+ /**
69
+ * Unique identifier for the destination.
70
+ *
71
+ * @remarks Prefixed with `sdst_`.
72
+ */
73
+ id: z.string().describe('Unique identifier for the destination.'),
74
+ /**
75
+ * The ID of the parent schedule.
76
+ */
77
+ schedule_id: z.string().describe('The ID of the parent schedule.'),
78
+ /**
79
+ * ISO 8601 timestamp when the destination was created.
80
+ */
81
+ created_at: z.string().describe('ISO 8601 timestamp when the destination was created.'),
82
+ /**
83
+ * ISO 8601 timestamp when the destination was last updated.
84
+ */
85
+ updated_at: z.string().describe('ISO 8601 timestamp when the destination was last updated.'),
86
+ /**
87
+ * ID of the user who created the destination.
88
+ */
89
+ created_by: z.string().describe('ID of the user who created the destination.'),
90
+ /**
91
+ * The destination type: `'url'` for HTTP endpoints or `'sandbox'` for Agentuity sandbox execution.
92
+ */
93
+ type: z
94
+ .enum(['url', 'sandbox'])
95
+ .describe("The destination type: `'url'` for HTTP endpoints or `'sandbox'` for Agentuity sandbox execution."),
96
+ /**
97
+ * Type-specific destination configuration.
98
+ *
99
+ * @remarks
100
+ * For `'url'` type:
101
+ * ```typescript
102
+ * { url: string; headers?: Record<string, string>; method?: string }
103
+ * ```
104
+ * For `'sandbox'` type: sandbox-specific configuration.
105
+ */
106
+ config: z.record(z.string(), z.unknown()).describe('Type-specific destination configuration.'),
107
+ });
108
+ /**
109
+ * A record of a single delivery attempt for a scheduled execution.
110
+ *
111
+ * Each time a schedule fires, one delivery record is created per destination.
112
+ * Failed deliveries may be retried automatically.
113
+ */
114
+ export const ScheduleDeliverySchema = z.object({
115
+ /**
116
+ * Unique identifier for the delivery attempt.
117
+ */
118
+ id: z.string().describe('Unique identifier for the delivery attempt.'),
119
+ /**
120
+ * ISO 8601 timestamp when the delivery was attempted.
121
+ */
122
+ date: z.string().describe('ISO 8601 timestamp when the delivery was attempted.'),
123
+ /**
124
+ * The ID of the schedule that triggered this delivery.
125
+ */
126
+ schedule_id: z.string().describe('The ID of the schedule that triggered this delivery.'),
127
+ /**
128
+ * The ID of the destination this delivery was sent to.
129
+ */
130
+ schedule_destination_id: z
131
+ .string()
132
+ .describe('The ID of the destination this delivery was sent to.'),
133
+ /**
134
+ * Delivery status: `'pending'` (queued), `'success'` (delivered), or `'failed'` (delivery error).
135
+ */
136
+ status: z
137
+ .enum(['pending', 'success', 'failed'])
138
+ .describe("Delivery status: `'pending'` (queued), `'success'` (delivered), or `'failed'` (delivery error)."),
139
+ /**
140
+ * Number of retry attempts made for this delivery.
141
+ */
142
+ retries: z.number().describe('Number of retry attempts made for this delivery.'),
143
+ /**
144
+ * Error message if the delivery failed, `null` on success.
145
+ */
146
+ error: z
147
+ .string()
148
+ .nullable()
149
+ .describe('Error message if the delivery failed, `null` on success.'),
150
+ /**
151
+ * The response received from the destination, or `null` if no response.
152
+ */
153
+ response: z
154
+ .record(z.string(), z.unknown())
155
+ .nullable()
156
+ .describe('The response received from the destination, or `null` if no response.'),
157
+ });
158
+ /**
159
+ * Parameters for creating a new schedule.
160
+ */
161
+ export const CreateScheduleParamsSchema = z.object({
162
+ /**
163
+ * Human-readable name for the schedule.
164
+ */
165
+ name: z.string().describe('Human-readable name for the schedule.'),
166
+ /**
167
+ * Optional description of the schedule's purpose.
168
+ */
169
+ description: z.string().optional().describe("Optional description of the schedule's purpose."),
170
+ /**
171
+ * Cron expression defining when the schedule fires
172
+ * (e.g., `'0 * * * *'` for every hour).
173
+ *
174
+ * @remarks Must be a valid cron expression. Validated by the server on creation.
175
+ * Supports standard five-field cron syntax including step values.
176
+ */
177
+ expression: z.string().describe('Cron expression defining when the schedule fires'),
178
+ /**
179
+ * Whether this is a system-managed schedule.
180
+ *
181
+ * @remarks Internal schedules are created by the system for workflows and cannot
182
+ * be modified or deleted directly by users.
183
+ */
184
+ internal: z.boolean().optional().describe('Whether this is a system-managed schedule.'),
185
+ /**
186
+ * Optional array of destinations to create alongside the schedule.
187
+ *
188
+ * @remarks Destinations are created atomically with the schedule — if any destination
189
+ * fails validation, the entire creation is rolled back.
190
+ */
191
+ destinations: z
192
+ .array(z.lazy(() => CreateScheduleDestinationParamsSchema))
193
+ .optional()
194
+ .describe('Optional array of destinations to create alongside the schedule.'),
195
+ });
196
+ /**
197
+ * Parameters for creating a new destination on a schedule.
198
+ */
199
+ export const CreateScheduleDestinationParamsSchema = z.object({
200
+ /**
201
+ * The destination type: `'url'` for HTTP endpoints or `'sandbox'` for Agentuity sandbox execution.
202
+ */
203
+ type: z
204
+ .enum(['url', 'sandbox'])
205
+ .describe("The destination type: `'url'` for HTTP endpoints or `'sandbox'` for Agentuity sandbox execution."),
206
+ /**
207
+ * Type-specific destination configuration.
208
+ *
209
+ * @remarks
210
+ * For `'url'` type:
211
+ * ```typescript
212
+ * { url: string; headers?: Record<string, string>; method?: string }
213
+ * ```
214
+ * For `'sandbox'` type: sandbox-specific configuration.
215
+ */
216
+ config: z.record(z.string(), z.unknown()).describe('Type-specific destination configuration.'),
217
+ });
218
+ /**
219
+ * Parameters for updating an existing schedule.
220
+ *
221
+ * All fields are optional; only provided fields are updated.
222
+ */
223
+ export const UpdateScheduleParamsSchema = z.object({
224
+ /**
225
+ * Updated human-readable name for the schedule.
226
+ */
227
+ name: z.string().optional().describe('Updated human-readable name for the schedule.'),
228
+ /**
229
+ * Updated description.
230
+ */
231
+ description: z.string().optional().describe('Updated description.'),
232
+ /**
233
+ * Updated cron expression. If changed, the `due_date` is automatically recomputed.
234
+ *
235
+ * @remarks Must be a valid cron expression. Validated by the server on update.
236
+ */
237
+ expression: z
238
+ .string()
239
+ .optional()
240
+ .describe('Updated cron expression. If changed, the `due_date` is automatically recomputed.'),
241
+ });
242
+ /**
243
+ * Paginated list of schedules.
244
+ */
245
+ export const ScheduleListResultSchema = z.object({
246
+ /**
247
+ * Array of schedule records for the current page.
248
+ */
249
+ schedules: z.array(ScheduleSchema).describe('Array of schedule records for the current page.'),
250
+ /**
251
+ * Total number of schedules across all pages.
252
+ */
253
+ total: z.number().describe('Total number of schedules across all pages.'),
254
+ });
255
+ /**
256
+ * A schedule with its associated destinations.
257
+ */
258
+ export const ScheduleGetResultSchema = z.object({
259
+ /**
260
+ * The schedule record.
261
+ */
262
+ schedule: ScheduleSchema.describe('The schedule record.'),
263
+ /**
264
+ * Array of destinations configured for this schedule.
265
+ */
266
+ destinations: z
267
+ .array(ScheduleDestinationSchema)
268
+ .describe('Array of destinations configured for this schedule.'),
269
+ });
270
+ /**
271
+ * Result of creating a schedule, including any destinations created atomically.
272
+ */
273
+ export const ScheduleCreateResultSchema = z.object({
274
+ /**
275
+ * The newly created schedule record.
276
+ */
277
+ schedule: ScheduleSchema.describe('The newly created schedule record.'),
278
+ /**
279
+ * Array of destinations that were created alongside the schedule.
280
+ */
281
+ destinations: z
282
+ .array(ScheduleDestinationSchema)
283
+ .describe('Array of destinations that were created alongside the schedule.'),
284
+ });
285
+ /**
286
+ * List of delivery attempts for a schedule.
287
+ */
288
+ export const ScheduleDeliveryListResultSchema = z.object({
289
+ /**
290
+ * Array of delivery attempt records.
291
+ */
292
+ deliveries: z.array(ScheduleDeliverySchema).describe('Array of delivery attempt records.'),
293
+ });
294
+ /**
295
+ * Client for the Agentuity Schedule service.
296
+ *
297
+ * Provides methods for creating, managing, and monitoring cron-based scheduled jobs.
298
+ * Schedules fire at intervals defined by cron expressions and deliver HTTP requests
299
+ * to configured destinations (URLs or sandboxes).
300
+ *
301
+ * The service supports:
302
+ * - CRUD operations on schedules and their destinations
303
+ * - Cron expression validation
304
+ * - Delivery history and monitoring
305
+ * - Automatic due date computation from cron expressions
306
+ *
307
+ * All methods are instrumented with OpenTelemetry spans for observability.
308
+ *
309
+ * @example
310
+ * ```typescript
311
+ * const schedules = new ScheduleService(baseUrl, adapter);
312
+ *
313
+ * // Create a schedule that fires every hour
314
+ * const result = await schedules.create({
315
+ * name: 'Hourly Sync',
316
+ * expression: '0 * * * *',
317
+ * destinations: [{ type: 'url', config: { url: 'https://example.com/sync' } }],
318
+ * });
319
+ *
320
+ * // List all schedules
321
+ * const { schedules: list, total } = await schedules.list();
322
+ * ```
323
+ */
324
+ export class ScheduleService {
325
+ #adapter;
326
+ #baseUrl;
327
+ /**
328
+ * Create a new ScheduleService instance.
329
+ *
330
+ * @param baseUrl - The base URL for the Agentuity Schedule API (e.g., `https://api.agentuity.com`)
331
+ * @param adapter - The HTTP fetch adapter used for making API requests
332
+ */
333
+ constructor(baseUrl, adapter) {
334
+ this.#adapter = adapter;
335
+ this.#baseUrl = baseUrl;
336
+ }
337
+ /**
338
+ * Create a new schedule with optional destinations.
339
+ *
340
+ * The schedule and its destinations are created atomically — if any validation
341
+ * fails, the entire operation is rolled back.
342
+ *
343
+ * @param params - The schedule creation parameters including name, cron expression, and optional destinations
344
+ * @returns The created schedule and its destinations
345
+ * @throws ServiceException on API errors (e.g., invalid cron expression, invalid destination URL)
346
+ *
347
+ * @example
348
+ * ```typescript
349
+ * const result = await schedules.create({
350
+ * name: 'Daily Report',
351
+ * description: 'Generate and send daily reports',
352
+ * expression: '0 9 * * *',
353
+ * destinations: [
354
+ * { type: 'url', config: { url: 'https://example.com/reports' } },
355
+ * ],
356
+ * });
357
+ * console.log('Created schedule:', result.schedule.id);
358
+ * console.log('Next run:', result.schedule.due_date);
359
+ * ```
360
+ */
361
+ async create(params) {
362
+ const url = buildUrl(this.#baseUrl, '/schedule/create');
363
+ const signal = AbortSignal.timeout(30_000);
364
+ const res = await this.#adapter.invoke(url, {
365
+ method: 'POST',
366
+ signal,
367
+ body: JSON.stringify(params),
368
+ contentType: 'application/json',
369
+ telemetry: {
370
+ name: 'agentuity.schedule.create',
371
+ attributes: {
372
+ destinationCount: String(params.destinations?.length ?? 0),
373
+ name: params.name,
374
+ },
375
+ },
376
+ });
377
+ if (res.ok) {
378
+ return res.data;
379
+ }
380
+ throw await toServiceException('POST', url, res.response);
381
+ }
382
+ /**
383
+ * List all schedules with optional pagination.
384
+ *
385
+ * @param params - Optional pagination parameters
386
+ * @param params.limit - Maximum number of schedules to return (max 500)
387
+ * @param params.offset - Number of schedules to skip for pagination
388
+ * @returns A paginated list of schedules with the total count
389
+ * @throws ServiceException on API errors
390
+ *
391
+ * @example
392
+ * ```typescript
393
+ * // List first page
394
+ * const { schedules, total } = await service.list({ limit: 20 });
395
+ * console.log(`Showing ${schedules.length} of ${total} schedules`);
396
+ *
397
+ * // Paginate through all schedules
398
+ * const page2 = await service.list({ limit: 20, offset: 20 });
399
+ * ```
400
+ */
401
+ async list(params) {
402
+ const qs = new URLSearchParams();
403
+ if (params?.limit !== undefined) {
404
+ qs.set('limit', String(params.limit));
405
+ }
406
+ if (params?.offset !== undefined) {
407
+ qs.set('offset', String(params.offset));
408
+ }
409
+ const path = qs.toString() ? `/schedule/list?${qs.toString()}` : '/schedule/list';
410
+ const url = buildUrl(this.#baseUrl, path);
411
+ const signal = AbortSignal.timeout(30_000);
412
+ const res = await this.#adapter.invoke(url, {
413
+ method: 'GET',
414
+ signal,
415
+ telemetry: {
416
+ name: 'agentuity.schedule.list',
417
+ attributes: {
418
+ limit: String(params?.limit ?? ''),
419
+ offset: String(params?.offset ?? ''),
420
+ },
421
+ },
422
+ });
423
+ if (res.ok) {
424
+ return res.data;
425
+ }
426
+ throw await toServiceException('GET', url, res.response);
427
+ }
428
+ /**
429
+ * Get a schedule by its ID, including all configured destinations.
430
+ *
431
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
432
+ * @returns The schedule record and its array of destinations
433
+ * @throws ServiceException on API errors (including 404 if not found)
434
+ *
435
+ * @example
436
+ * ```typescript
437
+ * const { schedule, destinations } = await service.get('sch_abc123');
438
+ * console.log('Schedule:', schedule.name);
439
+ * console.log('Next run:', schedule.due_date);
440
+ * console.log('Destinations:', destinations.length);
441
+ * ```
442
+ */
443
+ async get(scheduleId) {
444
+ const url = buildUrl(this.#baseUrl, `/schedule/get/${encodeURIComponent(scheduleId)}`);
445
+ const signal = AbortSignal.timeout(30_000);
446
+ const res = await this.#adapter.invoke(url, {
447
+ method: 'GET',
448
+ signal,
449
+ telemetry: {
450
+ name: 'agentuity.schedule.get',
451
+ attributes: {
452
+ scheduleId,
453
+ },
454
+ },
455
+ });
456
+ if (res.ok) {
457
+ return res.data;
458
+ }
459
+ if (res.response.status === 404) {
460
+ throw await toServiceException('GET', url, res.response);
461
+ }
462
+ throw await toServiceException('GET', url, res.response);
463
+ }
464
+ /**
465
+ * Update an existing schedule. Only the provided fields are modified.
466
+ *
467
+ * @remarks If the `expression` field is changed, the `due_date` is automatically
468
+ * recomputed based on the new cron expression.
469
+ *
470
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
471
+ * @param params - The fields to update (all optional)
472
+ * @returns The updated schedule record
473
+ * @throws ServiceException on API errors (e.g., invalid cron expression, schedule not found)
474
+ *
475
+ * @example
476
+ * ```typescript
477
+ * // Update the name and expression
478
+ * const { schedule } = await service.update('sch_abc123', {
479
+ * name: 'Daily Midnight Sync',
480
+ * expression: '0 0 * * *',
481
+ * });
482
+ * console.log('Updated. Next run:', schedule.due_date);
483
+ * ```
484
+ */
485
+ async update(scheduleId, params) {
486
+ const url = buildUrl(this.#baseUrl, `/schedule/update/${encodeURIComponent(scheduleId)}`);
487
+ const signal = AbortSignal.timeout(30_000);
488
+ const res = await this.#adapter.invoke(url, {
489
+ method: 'PUT',
490
+ signal,
491
+ body: JSON.stringify(params),
492
+ contentType: 'application/json',
493
+ telemetry: {
494
+ name: 'agentuity.schedule.update',
495
+ attributes: {
496
+ scheduleId,
497
+ },
498
+ },
499
+ });
500
+ if (res.ok) {
501
+ return res.data;
502
+ }
503
+ throw await toServiceException('PUT', url, res.response);
504
+ }
505
+ /**
506
+ * Delete a schedule and all of its destinations and delivery history.
507
+ *
508
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
509
+ * @throws ServiceException on API errors (e.g., schedule not found)
510
+ *
511
+ * @example
512
+ * ```typescript
513
+ * await service.delete('sch_abc123');
514
+ * console.log('Schedule deleted');
515
+ * ```
516
+ */
517
+ async delete(scheduleId) {
518
+ const url = buildUrl(this.#baseUrl, `/schedule/delete/${encodeURIComponent(scheduleId)}`);
519
+ const signal = AbortSignal.timeout(30_000);
520
+ const res = await this.#adapter.invoke(url, {
521
+ method: 'DELETE',
522
+ signal,
523
+ telemetry: {
524
+ name: 'agentuity.schedule.delete',
525
+ attributes: {
526
+ scheduleId,
527
+ },
528
+ },
529
+ });
530
+ if (res.ok) {
531
+ return;
532
+ }
533
+ throw await toServiceException('DELETE', url, res.response);
534
+ }
535
+ /**
536
+ * Create a new destination on an existing schedule.
537
+ *
538
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
539
+ * @param params - The destination configuration including type and type-specific config
540
+ * @returns The newly created destination record
541
+ * @throws ServiceException on API errors (e.g., invalid URL, schedule not found)
542
+ *
543
+ * @example
544
+ * ```typescript
545
+ * const { destination } = await service.createDestination('sch_abc123', {
546
+ * type: 'url',
547
+ * config: {
548
+ * url: 'https://example.com/webhook',
549
+ * headers: { 'Authorization': 'Bearer token' },
550
+ * },
551
+ * });
552
+ * console.log('Destination created:', destination.id);
553
+ * ```
554
+ */
555
+ async createDestination(scheduleId, params) {
556
+ const url = buildUrl(this.#baseUrl, `/schedule/destinations/create/${encodeURIComponent(scheduleId)}`);
557
+ const signal = AbortSignal.timeout(30_000);
558
+ const res = await this.#adapter.invoke(url, {
559
+ method: 'POST',
560
+ signal,
561
+ body: JSON.stringify(params),
562
+ contentType: 'application/json',
563
+ telemetry: {
564
+ name: 'agentuity.schedule.createDestination',
565
+ attributes: {
566
+ scheduleId,
567
+ type: params.type,
568
+ },
569
+ },
570
+ });
571
+ if (res.ok) {
572
+ return res.data;
573
+ }
574
+ throw await toServiceException('POST', url, res.response);
575
+ }
576
+ /**
577
+ * Delete a destination from a schedule.
578
+ *
579
+ * @param destinationId - The destination ID (prefixed with `sdst_`)
580
+ * @throws ServiceException on API errors (e.g., destination not found)
581
+ *
582
+ * @example
583
+ * ```typescript
584
+ * await service.deleteDestination('sdst_xyz789');
585
+ * console.log('Destination removed');
586
+ * ```
587
+ */
588
+ async deleteDestination(destinationId) {
589
+ const url = buildUrl(this.#baseUrl, `/schedule/destinations/delete/${encodeURIComponent(destinationId)}`);
590
+ const signal = AbortSignal.timeout(30_000);
591
+ const res = await this.#adapter.invoke(url, {
592
+ method: 'DELETE',
593
+ signal,
594
+ telemetry: {
595
+ name: 'agentuity.schedule.deleteDestination',
596
+ attributes: {
597
+ destinationId,
598
+ },
599
+ },
600
+ });
601
+ if (res.ok) {
602
+ return;
603
+ }
604
+ throw await toServiceException('DELETE', url, res.response);
605
+ }
606
+ /**
607
+ * List delivery attempts for a schedule with optional pagination.
608
+ *
609
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
610
+ * @param params - Optional pagination parameters
611
+ * @param params.limit - Maximum number of deliveries to return
612
+ * @param params.offset - Number of deliveries to skip for pagination
613
+ * @returns A list of delivery attempt records
614
+ * @throws ServiceException on API errors (including 404 if schedule not found)
615
+ *
616
+ * @example
617
+ * ```typescript
618
+ * const { deliveries } = await service.listDeliveries('sch_abc123');
619
+ * for (const d of deliveries) {
620
+ * console.log(`${d.date}: ${d.status} (retries: ${d.retries})`);
621
+ * if (d.error) {
622
+ * console.error(' Error:', d.error);
623
+ * }
624
+ * }
625
+ * ```
626
+ */
627
+ async listDeliveries(scheduleId, params) {
628
+ const qs = new URLSearchParams();
629
+ if (params?.limit !== undefined) {
630
+ qs.set('limit', String(params.limit));
631
+ }
632
+ if (params?.offset !== undefined) {
633
+ qs.set('offset', String(params.offset));
634
+ }
635
+ const basePath = `/schedule/deliveries/${encodeURIComponent(scheduleId)}`;
636
+ const path = qs.toString() ? `${basePath}?${qs.toString()}` : basePath;
637
+ const url = buildUrl(this.#baseUrl, path);
638
+ const signal = AbortSignal.timeout(30_000);
639
+ const res = await this.#adapter.invoke(url, {
640
+ method: 'GET',
641
+ signal,
642
+ telemetry: {
643
+ name: 'agentuity.schedule.listDeliveries',
644
+ attributes: {
645
+ scheduleId,
646
+ limit: String(params?.limit ?? ''),
647
+ offset: String(params?.offset ?? ''),
648
+ },
649
+ },
650
+ });
651
+ if (res.ok) {
652
+ return res.data;
653
+ }
654
+ if (res.response.status === 404) {
655
+ throw await toServiceException('GET', url, res.response);
656
+ }
657
+ throw await toServiceException('GET', url, res.response);
658
+ }
659
+ /**
660
+ * Get a specific destination for a schedule by its ID.
661
+ *
662
+ * @remarks This is a convenience method that fetches the schedule and filters
663
+ * its destinations client-side. For large destination lists, prefer using
664
+ * {@link get} directly.
665
+ *
666
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
667
+ * @param destinationId - The destination ID (prefixed with `sdst_`)
668
+ * @returns The matching destination record
669
+ * @throws Error if the destination is not found within the schedule
670
+ * @throws ServiceException on API errors when fetching the schedule
671
+ *
672
+ * @example
673
+ * ```typescript
674
+ * const dest = await service.getDestination('sch_abc123', 'sdst_xyz789');
675
+ * console.log('Destination type:', dest.type);
676
+ * console.log('Config:', dest.config);
677
+ * ```
678
+ */
679
+ async getDestination(scheduleId, destinationId) {
680
+ const result = await this.get(scheduleId);
681
+ const destination = result.destinations.find((d) => d.id === destinationId);
682
+ if (!destination) {
683
+ throw new Error(`Destination not found: ${destinationId}`);
684
+ }
685
+ return destination;
686
+ }
687
+ /**
688
+ * Get a specific delivery record by its ID.
689
+ *
690
+ * @remarks This is a convenience method that lists deliveries and filters
691
+ * client-side. Use the optional `params` to control the search window if
692
+ * the delivery may not be in the first page of results.
693
+ *
694
+ * @param scheduleId - The schedule ID (prefixed with `sch_`)
695
+ * @param deliveryId - The delivery ID to find
696
+ * @param params - Optional pagination parameters to control the search window
697
+ * @returns The matching delivery record
698
+ * @throws Error if the delivery is not found in the result set
699
+ * @throws ServiceException on API errors when listing deliveries
700
+ *
701
+ * @example
702
+ * ```typescript
703
+ * const delivery = await service.getDelivery('sch_abc123', 'del_xyz789');
704
+ * console.log('Status:', delivery.status);
705
+ * console.log('Retries:', delivery.retries);
706
+ * ```
707
+ */
708
+ async getDelivery(scheduleId, deliveryId, params) {
709
+ const result = await this.listDeliveries(scheduleId, params);
710
+ const delivery = result.deliveries.find((d) => d.id === deliveryId);
711
+ if (!delivery) {
712
+ throw new Error(`Delivery not found: ${deliveryId}`);
713
+ }
714
+ return delivery;
715
+ }
716
+ }
717
+ //# sourceMappingURL=service.js.map