@agentuity/core 1.0.34 → 1.0.36
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/services/db/index.d.ts +1 -0
- package/dist/services/db/index.d.ts.map +1 -1
- package/dist/services/db/index.js +1 -0
- package/dist/services/db/index.js.map +1 -1
- package/dist/services/db/stats.d.ts +146 -0
- package/dist/services/db/stats.d.ts.map +1 -0
- package/dist/services/db/stats.js +94 -0
- package/dist/services/db/stats.js.map +1 -0
- package/dist/services/keyvalue/service.d.ts +3 -3
- package/dist/services/keyvalue/service.d.ts.map +1 -1
- package/dist/services/keyvalue/service.js +6 -6
- package/dist/services/keyvalue/service.js.map +1 -1
- package/dist/services/queue/types.d.ts.map +1 -1
- package/dist/services/queue/types.js +8 -2
- package/dist/services/queue/types.js.map +1 -1
- package/dist/services/queue/websocket.d.ts.map +1 -1
- package/dist/services/queue/websocket.js +27 -8
- package/dist/services/queue/websocket.js.map +1 -1
- package/dist/services/sandbox/types.d.ts.map +1 -1
- package/dist/services/sandbox/types.js.map +1 -1
- package/dist/services/webhook/analytics.d.ts +77 -0
- package/dist/services/webhook/analytics.d.ts.map +1 -0
- package/dist/services/webhook/analytics.js +56 -0
- package/dist/services/webhook/analytics.js.map +1 -0
- package/dist/services/webhook/destinations.d.ts +4 -0
- package/dist/services/webhook/destinations.d.ts.map +1 -1
- package/dist/services/webhook/index.d.ts +2 -1
- package/dist/services/webhook/index.d.ts.map +1 -1
- package/dist/services/webhook/index.js +5 -1
- package/dist/services/webhook/index.js.map +1 -1
- package/dist/services/webhook/service.d.ts +43 -1
- package/dist/services/webhook/service.d.ts.map +1 -1
- package/dist/services/webhook/service.js +74 -0
- package/dist/services/webhook/service.js.map +1 -1
- package/dist/services/webhook/types.d.ts +79 -0
- package/dist/services/webhook/types.d.ts.map +1 -1
- package/dist/services/webhook/types.js +62 -0
- package/dist/services/webhook/types.js.map +1 -1
- package/dist/services/webhook/webhooks.d.ts +4 -0
- package/dist/services/webhook/webhooks.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/services/db/index.ts +15 -0
- package/src/services/db/stats.ts +121 -0
- package/src/services/keyvalue/service.ts +6 -6
- package/src/services/queue/types.ts +12 -2
- package/src/services/queue/websocket.ts +32 -8
- package/src/services/sandbox/types.ts +0 -1
- package/src/services/webhook/analytics.ts +80 -0
- package/src/services/webhook/index.ts +25 -0
- package/src/services/webhook/service.ts +124 -0
- package/src/services/webhook/types.ts +92 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type APIClient, APIResponseSchema } from '../api.ts';
|
|
3
|
+
import { DbInvalidArgumentError, DbResponseError } from './util.ts';
|
|
4
|
+
|
|
5
|
+
// Request schema
|
|
6
|
+
export const DbLogStatsRequestSchema = z.object({
|
|
7
|
+
database: z.string().describe('the database name'),
|
|
8
|
+
orgId: z.string().describe('the organization ID'),
|
|
9
|
+
region: z.string().describe('the region'),
|
|
10
|
+
startDate: z.string().describe('start date filter (ISO 8601)'),
|
|
11
|
+
endDate: z.string().describe('end date filter (ISO 8601)'),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Summary stats
|
|
15
|
+
export const DbLogStatsSummarySchema = z.object({
|
|
16
|
+
totalQueries: z.number().describe('total number of queries'),
|
|
17
|
+
errorCount: z.number().describe('number of queries with errors'),
|
|
18
|
+
avgDuration: z.number().describe('average query duration in ms'),
|
|
19
|
+
p50Duration: z.number().describe('50th percentile duration in ms'),
|
|
20
|
+
p95Duration: z.number().describe('95th percentile duration in ms'),
|
|
21
|
+
p99Duration: z.number().describe('99th percentile duration in ms'),
|
|
22
|
+
maxDuration: z.number().describe('maximum query duration in ms'),
|
|
23
|
+
totalRows: z.number().describe('total rows affected/returned'),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Time series point
|
|
27
|
+
export const DbLogStatsTimeSeriesPointSchema = z.object({
|
|
28
|
+
timestamp: z.string().describe('bucket timestamp'),
|
|
29
|
+
queryCount: z.number().describe('queries in this bucket'),
|
|
30
|
+
errorCount: z.number().describe('errors in this bucket'),
|
|
31
|
+
avgDuration: z.number().describe('average duration in this bucket'),
|
|
32
|
+
p50Duration: z.number().describe('p50 duration in this bucket'),
|
|
33
|
+
p95Duration: z.number().describe('p95 duration in this bucket'),
|
|
34
|
+
p99Duration: z.number().describe('p99 duration in this bucket'),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Query pattern
|
|
38
|
+
export const DbLogStatsQueryPatternSchema = z.object({
|
|
39
|
+
pattern: z.string().describe('SQL query text'),
|
|
40
|
+
command: z.string().describe('SQL command type'),
|
|
41
|
+
calls: z.number().describe('number of executions'),
|
|
42
|
+
avgDuration: z.number().describe('average duration in ms'),
|
|
43
|
+
p95Duration: z.number().describe('95th percentile duration in ms'),
|
|
44
|
+
maxDuration: z.number().describe('maximum duration in ms'),
|
|
45
|
+
totalDuration: z.number().describe('total cumulative duration in ms'),
|
|
46
|
+
avgRows: z.number().describe('average rows affected'),
|
|
47
|
+
errors: z.number().describe('number of errors'),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Command breakdown
|
|
51
|
+
export const DbLogStatsCommandBreakdownSchema = z.object({
|
|
52
|
+
command: z.string().describe('SQL command type'),
|
|
53
|
+
queryCount: z.number().describe('number of queries'),
|
|
54
|
+
avgDuration: z.number().describe('average duration in ms'),
|
|
55
|
+
p95Duration: z.number().describe('95th percentile duration in ms'),
|
|
56
|
+
totalDuration: z.number().describe('total cumulative duration in ms'),
|
|
57
|
+
errorCount: z.number().describe('number of errors'),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Combined response
|
|
61
|
+
export const DbLogStatsResponseSchema = z.object({
|
|
62
|
+
summary: DbLogStatsSummarySchema,
|
|
63
|
+
timeSeries: z.array(DbLogStatsTimeSeriesPointSchema),
|
|
64
|
+
queryPatterns: z.array(DbLogStatsQueryPatternSchema),
|
|
65
|
+
commandBreakdown: z.array(DbLogStatsCommandBreakdownSchema),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const DbLogStatsAPIResponseSchema = APIResponseSchema(DbLogStatsResponseSchema);
|
|
69
|
+
|
|
70
|
+
// Type exports
|
|
71
|
+
export type DbLogStatsSummary = z.infer<typeof DbLogStatsSummarySchema>;
|
|
72
|
+
export type DbLogStatsTimeSeriesPoint = z.infer<typeof DbLogStatsTimeSeriesPointSchema>;
|
|
73
|
+
export type DbLogStatsQueryPattern = z.infer<typeof DbLogStatsQueryPatternSchema>;
|
|
74
|
+
export type DbLogStatsCommandBreakdown = z.infer<typeof DbLogStatsCommandBreakdownSchema>;
|
|
75
|
+
export type DbLogStatsResponse = z.infer<typeof DbLogStatsResponseSchema>;
|
|
76
|
+
|
|
77
|
+
type DbLogStatsRequest = z.infer<typeof DbLogStatsRequestSchema>;
|
|
78
|
+
type DbLogStatsAPIResponse = z.infer<typeof DbLogStatsAPIResponseSchema>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get query performance stats for a database
|
|
82
|
+
*/
|
|
83
|
+
export async function dbLogStats(
|
|
84
|
+
client: APIClient,
|
|
85
|
+
request: DbLogStatsRequest
|
|
86
|
+
): Promise<DbLogStatsResponse> {
|
|
87
|
+
if (!request) {
|
|
88
|
+
throw new DbInvalidArgumentError({
|
|
89
|
+
message: 'request is required',
|
|
90
|
+
orgId: undefined,
|
|
91
|
+
region: undefined,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const { database, orgId, region, startDate, endDate } = request;
|
|
96
|
+
|
|
97
|
+
if (!orgId || !region || !database || !startDate || !endDate) {
|
|
98
|
+
throw new DbInvalidArgumentError({
|
|
99
|
+
message: 'orgId, region, database, startDate, and endDate are required',
|
|
100
|
+
orgId,
|
|
101
|
+
region,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const params = new URLSearchParams();
|
|
106
|
+
params.append('startDate', startDate);
|
|
107
|
+
params.append('endDate', endDate);
|
|
108
|
+
|
|
109
|
+
const url = `/resource/${encodeURIComponent(orgId)}/${encodeURIComponent(region)}/${encodeURIComponent(database)}/logs/stats?${params.toString()}`;
|
|
110
|
+
|
|
111
|
+
const resp = await client.get<DbLogStatsAPIResponse>(url, DbLogStatsAPIResponseSchema);
|
|
112
|
+
|
|
113
|
+
if (resp.success) {
|
|
114
|
+
return resp.data;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
throw new DbResponseError({
|
|
118
|
+
database,
|
|
119
|
+
message: resp.message || 'Failed to fetch database performance stats',
|
|
120
|
+
});
|
|
121
|
+
}
|
|
@@ -9,9 +9,9 @@ import { z } from 'zod';
|
|
|
9
9
|
export const KV_MIN_TTL_SECONDS = 60;
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Maximum TTL value in seconds (
|
|
12
|
+
* Maximum TTL value in seconds (365 days)
|
|
13
13
|
*/
|
|
14
|
-
export const KV_MAX_TTL_SECONDS =
|
|
14
|
+
export const KV_MAX_TTL_SECONDS = 31536000;
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Default TTL value in seconds (7 days) - used when namespace is auto-created or no TTL specified
|
|
@@ -88,11 +88,11 @@ export const KeyValueStorageSetParamsSchema = z.object({
|
|
|
88
88
|
* Time-to-live in seconds for the key. Controls when the key expires and is automatically deleted.
|
|
89
89
|
* - `undefined` (not provided): Key inherits the namespace's default TTL (7 days if not configured)
|
|
90
90
|
* - `null` or `0`: Key never expires
|
|
91
|
-
* - positive number (≥60): Key expires after the specified number of seconds (max
|
|
91
|
+
* - positive number (≥60): Key expires after the specified number of seconds (max 365 days)
|
|
92
92
|
*
|
|
93
93
|
* @remarks
|
|
94
94
|
* TTL values below 60 seconds are clamped to 60 seconds by the server.
|
|
95
|
-
* TTL values above
|
|
95
|
+
* TTL values above 31,536,000 seconds (365 days) are clamped to 365 days.
|
|
96
96
|
*/
|
|
97
97
|
ttl: z
|
|
98
98
|
.number()
|
|
@@ -117,7 +117,7 @@ export const CreateNamespaceParamsSchema = z.object({
|
|
|
117
117
|
* Default TTL for keys in this namespace (in seconds).
|
|
118
118
|
* - If undefined/omitted: uses server default (7 days / 604,800 seconds)
|
|
119
119
|
* - If 0: keys will not expire by default
|
|
120
|
-
* - If 60-
|
|
120
|
+
* - If 60-31,536,000: custom TTL in seconds (1 minute to 365 days)
|
|
121
121
|
*
|
|
122
122
|
* Keys can override this default by specifying TTL in the set() call.
|
|
123
123
|
* Active keys are automatically extended (sliding expiration) when read
|
|
@@ -444,7 +444,7 @@ export class KeyValueStorageService implements KeyValueStorage {
|
|
|
444
444
|
* - If TTL is null or 0, the key will not expire
|
|
445
445
|
* - If TTL is a positive number, the key expires after that many seconds
|
|
446
446
|
* - TTL values below 60 seconds are clamped to 60 seconds by the server
|
|
447
|
-
* - TTL values above
|
|
447
|
+
* - TTL values above 31,536,000 seconds (365 days) are clamped to 365 days
|
|
448
448
|
* - If the namespace doesn't exist, it is auto-created with a 7-day default TTL
|
|
449
449
|
*/
|
|
450
450
|
async set<T = unknown>(
|
|
@@ -1568,7 +1568,14 @@ export const ConsumerSchema = z
|
|
|
1568
1568
|
.object({
|
|
1569
1569
|
id: z.string().describe('Unique consumer identifier (qcns_ prefix).'),
|
|
1570
1570
|
queue_id: z.string().describe('Queue this consumer is connected to.'),
|
|
1571
|
-
client_id: z
|
|
1571
|
+
client_id: z
|
|
1572
|
+
.string()
|
|
1573
|
+
.max(256)
|
|
1574
|
+
.nullable()
|
|
1575
|
+
.optional()
|
|
1576
|
+
.describe(
|
|
1577
|
+
'Client-provided identifier (max 256 characters). Can be any string for your own identification purposes.'
|
|
1578
|
+
),
|
|
1572
1579
|
durable: z.boolean().describe('Whether this consumer uses durable offset tracking.'),
|
|
1573
1580
|
ip_address: z.string().nullable().optional().describe('IP address of the consumer.'),
|
|
1574
1581
|
last_offset: z.number().nullable().optional().describe('Last processed message offset.'),
|
|
@@ -1603,8 +1610,11 @@ export const WebSocketAuthRequestSchema = z
|
|
|
1603
1610
|
.describe('The API key for authentication (raw key, not "Bearer ...").'),
|
|
1604
1611
|
client_id: z
|
|
1605
1612
|
.string()
|
|
1613
|
+
.max(256)
|
|
1606
1614
|
.optional()
|
|
1607
|
-
.describe(
|
|
1615
|
+
.describe(
|
|
1616
|
+
'Optional client identifier (max 256 characters). Can be any string for your own identification purposes. If omitted, the server generates one. Store and reuse on reconnect for resume semantics.'
|
|
1617
|
+
),
|
|
1608
1618
|
last_offset: z
|
|
1609
1619
|
.number()
|
|
1610
1620
|
.optional()
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
*/
|
|
59
59
|
|
|
60
60
|
import { z } from 'zod';
|
|
61
|
+
import { getEnv } from '../env.ts';
|
|
61
62
|
import type { Message } from './types.ts';
|
|
62
63
|
import { WebSocketAuthResponseSchema, WebSocketMessageSchema } from './types.ts';
|
|
63
|
-
import { getEnv } from '../env.ts';
|
|
64
64
|
import { QueueError } from './util.ts';
|
|
65
65
|
import { validateQueueName } from './validation.ts';
|
|
66
66
|
|
|
@@ -106,7 +106,13 @@ export const QueueWebSocketOptionsSchema = z.object({
|
|
|
106
106
|
.describe('Maximum reconnect attempts before giving up'),
|
|
107
107
|
reconnectDelayMs: z.number().optional().describe('Initial reconnect delay in milliseconds'),
|
|
108
108
|
maxReconnectDelayMs: z.number().optional().describe('Maximum reconnect delay in milliseconds'),
|
|
109
|
-
clientId: z
|
|
109
|
+
clientId: z
|
|
110
|
+
.string()
|
|
111
|
+
.max(256)
|
|
112
|
+
.optional()
|
|
113
|
+
.describe(
|
|
114
|
+
'Optional client identifier (max 256 characters). Can be any string for your own identification. Reuse on reconnect for resume semantics.'
|
|
115
|
+
),
|
|
110
116
|
lastOffset: z
|
|
111
117
|
.number()
|
|
112
118
|
.optional()
|
|
@@ -140,7 +146,13 @@ export const SubscribeToQueueOptionsSchema = z.object({
|
|
|
140
146
|
.describe('Optional API key override; falls back to AGENTUITY_SDK_KEY'),
|
|
141
147
|
baseUrl: z.string().describe('Base Catalyst URL used to construct the WebSocket endpoint'),
|
|
142
148
|
signal: z.custom<AbortSignal>().optional().describe('AbortSignal used to stop the subscription'),
|
|
143
|
-
clientId: z
|
|
149
|
+
clientId: z
|
|
150
|
+
.string()
|
|
151
|
+
.max(256)
|
|
152
|
+
.optional()
|
|
153
|
+
.describe(
|
|
154
|
+
'Optional client identifier (max 256 characters). Can be any string for your own identification. Reuse on reconnect for resume semantics.'
|
|
155
|
+
),
|
|
144
156
|
lastOffset: z
|
|
145
157
|
.number()
|
|
146
158
|
.optional()
|
|
@@ -227,7 +239,7 @@ export function createQueueWebSocket(options: QueueWebSocketOptions): QueueWebSo
|
|
|
227
239
|
onClose,
|
|
228
240
|
onError,
|
|
229
241
|
autoReconnect = true,
|
|
230
|
-
maxReconnectAttempts =
|
|
242
|
+
maxReconnectAttempts = Number.POSITIVE_INFINITY,
|
|
231
243
|
reconnectDelayMs = 1000,
|
|
232
244
|
maxReconnectDelayMs = 30000,
|
|
233
245
|
orgId,
|
|
@@ -349,6 +361,12 @@ export function createQueueWebSocket(options: QueueWebSocketOptions): QueueWebSo
|
|
|
349
361
|
state = 'closed';
|
|
350
362
|
ws = null;
|
|
351
363
|
|
|
364
|
+
// Close codes 4000–4999 are application-level terminal errors
|
|
365
|
+
// (auth failure, validation error, etc.) — do not reconnect.
|
|
366
|
+
if (event.code >= 4000 && event.code < 5000) {
|
|
367
|
+
intentionallyClosed = true;
|
|
368
|
+
}
|
|
369
|
+
|
|
352
370
|
onClose?.(event.code, event.reason);
|
|
353
371
|
|
|
354
372
|
// Reconnect on any unintentional close — whether we were fully
|
|
@@ -383,7 +401,7 @@ export function createQueueWebSocket(options: QueueWebSocketOptions): QueueWebSo
|
|
|
383
401
|
}
|
|
384
402
|
|
|
385
403
|
// Exponential backoff with jitter, capped at maxReconnectDelayMs.
|
|
386
|
-
const baseDelay = reconnectDelayMs *
|
|
404
|
+
const baseDelay = reconnectDelayMs * 2 ** reconnectAttempts;
|
|
387
405
|
const jitter = 0.5 + Math.random() * 0.5;
|
|
388
406
|
const delay = Math.min(Math.floor(baseDelay * jitter), maxReconnectDelayMs);
|
|
389
407
|
|
|
@@ -508,9 +526,15 @@ export async function* subscribeToQueue(
|
|
|
508
526
|
// it to be thrown on clean shutdown / abort.
|
|
509
527
|
}
|
|
510
528
|
},
|
|
511
|
-
onClose: () => {
|
|
512
|
-
//
|
|
513
|
-
//
|
|
529
|
+
onClose: (code: number) => {
|
|
530
|
+
// Terminal close codes (4000–4999) mean the connection will not
|
|
531
|
+
// reconnect — signal the async iterator to stop so it doesn't
|
|
532
|
+
// hang forever. For abort-initiated closes, `finish()` is
|
|
533
|
+
// already called by the `onAbort` handler; calling it again is
|
|
534
|
+
// harmless (it's idempotent).
|
|
535
|
+
if (code >= 4000 && code < 5000) {
|
|
536
|
+
finish();
|
|
537
|
+
}
|
|
514
538
|
},
|
|
515
539
|
autoReconnect: true,
|
|
516
540
|
});
|
|
@@ -130,7 +130,6 @@ const SandboxSnapshotInfoBaseSchema = z.object({
|
|
|
130
130
|
/** Full name with org slug (@slug/name:tag) */
|
|
131
131
|
fullName: z.string().optional().describe('Full name with org slug (@slug/name:tag)'),
|
|
132
132
|
});
|
|
133
|
-
type SandboxSnapshotInfoBase = z.infer<typeof SandboxSnapshotInfoBaseSchema>;
|
|
134
133
|
|
|
135
134
|
/** Public snapshot information - includes org info */
|
|
136
135
|
export const SandboxSnapshotInfoPublicSchema = SandboxSnapshotInfoBaseSchema.extend({
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type APIClient, APIResponseSchema } from '../api.ts';
|
|
3
|
+
import {
|
|
4
|
+
type WebhookAnalyticsOptions,
|
|
5
|
+
type WebhookOrgAnalytics,
|
|
6
|
+
WebhookOrgAnalyticsSchema,
|
|
7
|
+
type WebhookTimeSeriesData,
|
|
8
|
+
WebhookTimeSeriesDataSchema,
|
|
9
|
+
} from './types.ts';
|
|
10
|
+
import { buildWebhookHeaders, WebhookError, webhookApiPathWithQuery } from './util.ts';
|
|
11
|
+
|
|
12
|
+
export const WebhookOrgAnalyticsResponseSchema = APIResponseSchema(
|
|
13
|
+
z.object({ analytics: WebhookOrgAnalyticsSchema })
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
export const WebhookTimeSeriesResponseSchema = APIResponseSchema(
|
|
17
|
+
z.object({ timeseries: WebhookTimeSeriesDataSchema })
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
function buildAnalyticsQuery(options?: WebhookAnalyticsOptions): string | undefined {
|
|
21
|
+
if (!options) return undefined;
|
|
22
|
+
const params = new URLSearchParams();
|
|
23
|
+
if (options.start) params.set('start', options.start);
|
|
24
|
+
if (options.end) params.set('end', options.end);
|
|
25
|
+
if (options.granularity) params.set('granularity', options.granularity);
|
|
26
|
+
const query = params.toString();
|
|
27
|
+
return query || undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get org-level webhook analytics summary.
|
|
32
|
+
*
|
|
33
|
+
* Returns total received, delivered, and failed counts for all webhooks in the org
|
|
34
|
+
* within the specified time period.
|
|
35
|
+
*
|
|
36
|
+
* @param client - The API client
|
|
37
|
+
* @param options - Analytics options (start, end, granularity)
|
|
38
|
+
* @returns Org-level webhook analytics
|
|
39
|
+
*/
|
|
40
|
+
export async function getWebhookOrgAnalytics(
|
|
41
|
+
client: APIClient,
|
|
42
|
+
options?: WebhookAnalyticsOptions
|
|
43
|
+
): Promise<WebhookOrgAnalytics> {
|
|
44
|
+
const queryString = buildAnalyticsQuery(options);
|
|
45
|
+
const url = webhookApiPathWithQuery('analytics/org', queryString);
|
|
46
|
+
const resp = await client.get(
|
|
47
|
+
url,
|
|
48
|
+
WebhookOrgAnalyticsResponseSchema,
|
|
49
|
+
undefined,
|
|
50
|
+
buildWebhookHeaders(options?.orgId)
|
|
51
|
+
);
|
|
52
|
+
if (resp.success) return resp.data.analytics;
|
|
53
|
+
throw new WebhookError({ message: resp.message || 'Failed to get webhook org analytics' });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get org-level webhook time series data.
|
|
58
|
+
*
|
|
59
|
+
* Returns time-bucketed received, delivered, and failed counts for all webhooks
|
|
60
|
+
* in the org within the specified time period.
|
|
61
|
+
*
|
|
62
|
+
* @param client - The API client
|
|
63
|
+
* @param options - Analytics options (start, end, granularity)
|
|
64
|
+
* @returns Webhook time series data
|
|
65
|
+
*/
|
|
66
|
+
export async function getWebhookOrgTimeSeries(
|
|
67
|
+
client: APIClient,
|
|
68
|
+
options?: WebhookAnalyticsOptions
|
|
69
|
+
): Promise<WebhookTimeSeriesData> {
|
|
70
|
+
const queryString = buildAnalyticsQuery(options);
|
|
71
|
+
const url = webhookApiPathWithQuery('analytics/org/timeseries', queryString);
|
|
72
|
+
const resp = await client.get(
|
|
73
|
+
url,
|
|
74
|
+
WebhookTimeSeriesResponseSchema,
|
|
75
|
+
undefined,
|
|
76
|
+
buildWebhookHeaders(options?.orgId)
|
|
77
|
+
);
|
|
78
|
+
if (resp.success) return resp.data.timeseries;
|
|
79
|
+
throw new WebhookError({ message: resp.message || 'Failed to get webhook org time series' });
|
|
80
|
+
}
|
|
@@ -68,6 +68,20 @@ export {
|
|
|
68
68
|
WebhookDestinationTypeSchema,
|
|
69
69
|
type WebhookReceipt,
|
|
70
70
|
WebhookReceiptSchema,
|
|
71
|
+
type WebhookAnalyticsGranularity,
|
|
72
|
+
WebhookAnalyticsGranularitySchema,
|
|
73
|
+
type WebhookAnalyticsOptions,
|
|
74
|
+
WebhookAnalyticsOptionsSchema,
|
|
75
|
+
type WebhookAnalyticsSummary,
|
|
76
|
+
WebhookAnalyticsSummarySchema,
|
|
77
|
+
type WebhookOrgAnalytics,
|
|
78
|
+
WebhookOrgAnalyticsSchema,
|
|
79
|
+
type WebhookTimePeriod,
|
|
80
|
+
WebhookTimePeriodSchema,
|
|
81
|
+
type WebhookTimeSeriesData,
|
|
82
|
+
WebhookTimeSeriesDataSchema,
|
|
83
|
+
type WebhookTimeSeriesPoint,
|
|
84
|
+
WebhookTimeSeriesPointSchema,
|
|
71
85
|
WebhookSchema,
|
|
72
86
|
} from './types.ts';
|
|
73
87
|
|
|
@@ -133,3 +147,14 @@ export {
|
|
|
133
147
|
WebhookDeliveriesListResponseSchema,
|
|
134
148
|
WebhookDeliveryResponseSchema,
|
|
135
149
|
} from './deliveries.ts';
|
|
150
|
+
|
|
151
|
+
// ============================================================================
|
|
152
|
+
// Analytics Operations
|
|
153
|
+
// ============================================================================
|
|
154
|
+
|
|
155
|
+
export {
|
|
156
|
+
getWebhookOrgAnalytics,
|
|
157
|
+
getWebhookOrgTimeSeries,
|
|
158
|
+
WebhookOrgAnalyticsResponseSchema,
|
|
159
|
+
WebhookTimeSeriesResponseSchema,
|
|
160
|
+
} from './analytics.ts';
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
Webhook,
|
|
9
9
|
WebhookDelivery,
|
|
10
10
|
WebhookDestination,
|
|
11
|
+
WebhookOrgAnalytics,
|
|
11
12
|
WebhookReceipt,
|
|
12
13
|
} from './types.ts';
|
|
13
14
|
|
|
@@ -773,4 +774,127 @@ export class WebhookService {
|
|
|
773
774
|
|
|
774
775
|
throw await toServiceException('POST', url, res.response);
|
|
775
776
|
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Get org-level webhook analytics summary.
|
|
780
|
+
*
|
|
781
|
+
* Returns total received, delivered, and failed counts for all webhooks
|
|
782
|
+
* in the org within the specified time period.
|
|
783
|
+
*
|
|
784
|
+
* @param options - Analytics options (start, end, granularity)
|
|
785
|
+
* @returns Org-level webhook analytics with period and summary
|
|
786
|
+
* @throws {@link ServiceException} if the API request fails
|
|
787
|
+
*/
|
|
788
|
+
async getOrgAnalytics(options?: {
|
|
789
|
+
start?: string;
|
|
790
|
+
end?: string;
|
|
791
|
+
granularity?: string;
|
|
792
|
+
}): Promise<WebhookOrgAnalytics> {
|
|
793
|
+
const params = new URLSearchParams();
|
|
794
|
+
if (options?.start) params.set('start', options.start);
|
|
795
|
+
if (options?.end) params.set('end', options.end);
|
|
796
|
+
if (options?.granularity) params.set('granularity', options.granularity);
|
|
797
|
+
const query = params.toString();
|
|
798
|
+
const path = query ? `/webhook/analytics/org?${query}` : '/webhook/analytics/org';
|
|
799
|
+
const url = buildUrl(this.#baseUrl, path);
|
|
800
|
+
const signal = createTimeoutSignal();
|
|
801
|
+
const res = await this.#adapter.invoke<
|
|
802
|
+
WebhookResponse<{
|
|
803
|
+
analytics: {
|
|
804
|
+
period: { start: string; end: string };
|
|
805
|
+
summary: { total_received: number; total_delivered: number; total_failed: number };
|
|
806
|
+
};
|
|
807
|
+
}>
|
|
808
|
+
>(url, {
|
|
809
|
+
method: 'GET',
|
|
810
|
+
signal,
|
|
811
|
+
telemetry: { name: 'agentuity.webhook.analytics.org' },
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
if (res.ok) {
|
|
815
|
+
if (res.data.success) {
|
|
816
|
+
const unwrapped = this.#unwrap<{
|
|
817
|
+
analytics: {
|
|
818
|
+
period: { start: string; end: string };
|
|
819
|
+
summary: {
|
|
820
|
+
total_received: number;
|
|
821
|
+
total_delivered: number;
|
|
822
|
+
total_failed: number;
|
|
823
|
+
};
|
|
824
|
+
};
|
|
825
|
+
}>(res.data.data);
|
|
826
|
+
return unwrapped.analytics;
|
|
827
|
+
}
|
|
828
|
+
throw new WebhookResponseError({ status: res.response.status, message: res.data.message });
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
throw await toServiceException('GET', url, res.response);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Get org-level webhook time series data.
|
|
836
|
+
*
|
|
837
|
+
* Returns time-bucketed received, delivered, and failed counts for all webhooks
|
|
838
|
+
* in the org within the specified time period.
|
|
839
|
+
*
|
|
840
|
+
* @param options - Analytics options (start, end, granularity)
|
|
841
|
+
* @returns Webhook time series data with period and series array
|
|
842
|
+
* @throws {@link ServiceException} if the API request fails
|
|
843
|
+
*/
|
|
844
|
+
async getOrgTimeSeries(options?: {
|
|
845
|
+
start?: string;
|
|
846
|
+
end?: string;
|
|
847
|
+
granularity?: string;
|
|
848
|
+
}): Promise<{
|
|
849
|
+
period: { start: string; end: string; granularity?: string };
|
|
850
|
+
series: Array<{ timestamp: string; received: number; delivered: number; failed: number }>;
|
|
851
|
+
}> {
|
|
852
|
+
const params = new URLSearchParams();
|
|
853
|
+
if (options?.start) params.set('start', options.start);
|
|
854
|
+
if (options?.end) params.set('end', options.end);
|
|
855
|
+
if (options?.granularity) params.set('granularity', options.granularity);
|
|
856
|
+
const query = params.toString();
|
|
857
|
+
const path = query
|
|
858
|
+
? `/webhook/analytics/org/timeseries?${query}`
|
|
859
|
+
: '/webhook/analytics/org/timeseries';
|
|
860
|
+
const url = buildUrl(this.#baseUrl, path);
|
|
861
|
+
const signal = createTimeoutSignal();
|
|
862
|
+
const res = await this.#adapter.invoke<
|
|
863
|
+
WebhookResponse<{
|
|
864
|
+
timeseries: {
|
|
865
|
+
period: { start: string; end: string; granularity?: string };
|
|
866
|
+
series: Array<{
|
|
867
|
+
timestamp: string;
|
|
868
|
+
received: number;
|
|
869
|
+
delivered: number;
|
|
870
|
+
failed: number;
|
|
871
|
+
}>;
|
|
872
|
+
};
|
|
873
|
+
}>
|
|
874
|
+
>(url, {
|
|
875
|
+
method: 'GET',
|
|
876
|
+
signal,
|
|
877
|
+
telemetry: { name: 'agentuity.webhook.analytics.org.timeseries' },
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
if (res.ok) {
|
|
881
|
+
if (res.data.success) {
|
|
882
|
+
const unwrapped = this.#unwrap<{
|
|
883
|
+
timeseries: {
|
|
884
|
+
period: { start: string; end: string; granularity?: string };
|
|
885
|
+
series: Array<{
|
|
886
|
+
timestamp: string;
|
|
887
|
+
received: number;
|
|
888
|
+
delivered: number;
|
|
889
|
+
failed: number;
|
|
890
|
+
}>;
|
|
891
|
+
};
|
|
892
|
+
}>(res.data.data);
|
|
893
|
+
return unwrapped.timeseries;
|
|
894
|
+
}
|
|
895
|
+
throw new WebhookResponseError({ status: res.response.status, message: res.data.message });
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
throw await toServiceException('GET', url, res.response);
|
|
899
|
+
}
|
|
776
900
|
}
|
|
@@ -40,6 +40,17 @@ export const WebhookSchema = z
|
|
|
40
40
|
.describe(
|
|
41
41
|
'Fully-qualified ingest URL for sending events to this webhook. Only present on create'
|
|
42
42
|
),
|
|
43
|
+
internal: z
|
|
44
|
+
.boolean()
|
|
45
|
+
.describe(
|
|
46
|
+
'Whether this is a system-managed webhook (e.g., S3 bucket notifications). Internal webhooks cannot be modified or deleted by users'
|
|
47
|
+
),
|
|
48
|
+
metadata: z
|
|
49
|
+
.record(z.string(), z.unknown())
|
|
50
|
+
.nullable()
|
|
51
|
+
.describe(
|
|
52
|
+
'System metadata for internal webhooks (e.g., bucket_name, type). Null for user-created webhooks'
|
|
53
|
+
),
|
|
43
54
|
})
|
|
44
55
|
.describe('Webhook endpoint configuration');
|
|
45
56
|
|
|
@@ -56,6 +67,17 @@ export const WebhookDestinationSchema = z
|
|
|
56
67
|
config: z
|
|
57
68
|
.record(z.string(), z.unknown())
|
|
58
69
|
.describe('Configuration object for the destination (e.g., URL, headers)'),
|
|
70
|
+
internal: z
|
|
71
|
+
.boolean()
|
|
72
|
+
.describe(
|
|
73
|
+
'Whether this is a system-managed destination. Internal destinations cannot be modified or deleted by users'
|
|
74
|
+
),
|
|
75
|
+
metadata: z
|
|
76
|
+
.record(z.string(), z.unknown())
|
|
77
|
+
.nullable()
|
|
78
|
+
.describe(
|
|
79
|
+
'System metadata for internal destinations (e.g., bucket_name, type). Null for user-created destinations'
|
|
80
|
+
),
|
|
59
81
|
})
|
|
60
82
|
.describe('Webhook destination representing a delivery target for webhook events');
|
|
61
83
|
|
|
@@ -98,6 +120,76 @@ export const WebhookDeliverySchema = z
|
|
|
98
120
|
|
|
99
121
|
export type WebhookDelivery = z.infer<typeof WebhookDeliverySchema>;
|
|
100
122
|
|
|
123
|
+
// ============================================================================
|
|
124
|
+
// Analytics Types
|
|
125
|
+
// ============================================================================
|
|
126
|
+
|
|
127
|
+
export const WebhookAnalyticsGranularitySchema = z
|
|
128
|
+
.enum(['minute', 'hour', 'day'])
|
|
129
|
+
.describe('Time bucket granularity for analytics queries');
|
|
130
|
+
|
|
131
|
+
export type WebhookAnalyticsGranularity = z.infer<typeof WebhookAnalyticsGranularitySchema>;
|
|
132
|
+
|
|
133
|
+
export const WebhookAnalyticsOptionsSchema = z
|
|
134
|
+
.object({
|
|
135
|
+
start: z.string().optional().describe('ISO 8601 start time for the analytics window'),
|
|
136
|
+
end: z.string().optional().describe('ISO 8601 end time for the analytics window'),
|
|
137
|
+
granularity: WebhookAnalyticsGranularitySchema.optional().describe('Time bucket granularity'),
|
|
138
|
+
orgId: z.string().optional().describe('Organization ID for CLI-authenticated requests'),
|
|
139
|
+
})
|
|
140
|
+
.describe('Options for webhook analytics queries');
|
|
141
|
+
|
|
142
|
+
export type WebhookAnalyticsOptions = z.infer<typeof WebhookAnalyticsOptionsSchema>;
|
|
143
|
+
|
|
144
|
+
export const WebhookTimePeriodSchema = z
|
|
145
|
+
.object({
|
|
146
|
+
start: z.string().describe('ISO 8601 start time'),
|
|
147
|
+
end: z.string().describe('ISO 8601 end time'),
|
|
148
|
+
granularity: WebhookAnalyticsGranularitySchema.optional(),
|
|
149
|
+
})
|
|
150
|
+
.describe('Time period for analytics data');
|
|
151
|
+
|
|
152
|
+
export type WebhookTimePeriod = z.infer<typeof WebhookTimePeriodSchema>;
|
|
153
|
+
|
|
154
|
+
export const WebhookAnalyticsSummarySchema = z
|
|
155
|
+
.object({
|
|
156
|
+
total_received: z.number().describe('Total webhook receipts in the period'),
|
|
157
|
+
total_delivered: z.number().describe('Total successful deliveries in the period'),
|
|
158
|
+
total_failed: z.number().describe('Total failed deliveries in the period'),
|
|
159
|
+
})
|
|
160
|
+
.describe('Summary analytics for webhook activity');
|
|
161
|
+
|
|
162
|
+
export type WebhookAnalyticsSummary = z.infer<typeof WebhookAnalyticsSummarySchema>;
|
|
163
|
+
|
|
164
|
+
export const WebhookOrgAnalyticsSchema = z
|
|
165
|
+
.object({
|
|
166
|
+
period: WebhookTimePeriodSchema,
|
|
167
|
+
summary: WebhookAnalyticsSummarySchema,
|
|
168
|
+
})
|
|
169
|
+
.describe('Org-level webhook analytics response');
|
|
170
|
+
|
|
171
|
+
export type WebhookOrgAnalytics = z.infer<typeof WebhookOrgAnalyticsSchema>;
|
|
172
|
+
|
|
173
|
+
export const WebhookTimeSeriesPointSchema = z
|
|
174
|
+
.object({
|
|
175
|
+
timestamp: z.string().describe('ISO 8601 timestamp for this data point'),
|
|
176
|
+
received: z.number().describe('Number of receipts in this bucket'),
|
|
177
|
+
delivered: z.number().describe('Number of successful deliveries in this bucket'),
|
|
178
|
+
failed: z.number().describe('Number of failed deliveries in this bucket'),
|
|
179
|
+
})
|
|
180
|
+
.describe('Single data point in webhook time series');
|
|
181
|
+
|
|
182
|
+
export type WebhookTimeSeriesPoint = z.infer<typeof WebhookTimeSeriesPointSchema>;
|
|
183
|
+
|
|
184
|
+
export const WebhookTimeSeriesDataSchema = z
|
|
185
|
+
.object({
|
|
186
|
+
period: WebhookTimePeriodSchema,
|
|
187
|
+
series: z.array(WebhookTimeSeriesPointSchema),
|
|
188
|
+
})
|
|
189
|
+
.describe('Webhook time series analytics data');
|
|
190
|
+
|
|
191
|
+
export type WebhookTimeSeriesData = z.infer<typeof WebhookTimeSeriesDataSchema>;
|
|
192
|
+
|
|
101
193
|
// ============================================================================
|
|
102
194
|
// API Options
|
|
103
195
|
// ============================================================================
|