@centrali-io/centrali-sdk 5.5.0 → 6.0.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.
- package/README.md +164 -14
- package/dist/index.d.ts +1807 -878
- package/dist/index.js +9153 -4076
- package/index.ts +61 -7152
- package/package.json +10 -3
- package/query-types.ts +83 -2
- package/scripts/smoke-types.ts +145 -5
- package/src/client.ts +1507 -0
- package/src/internal/auth.ts +35 -0
- package/src/internal/deprecation.ts +11 -0
- package/src/internal/error.ts +90 -0
- package/src/internal/paths.ts +456 -0
- package/src/internal/queryGuard.ts +21 -0
- package/src/managers/allowedDomains.ts +90 -0
- package/src/managers/anomalyInsights.ts +215 -0
- package/src/managers/auditLog.ts +105 -0
- package/src/managers/collections.ts +197 -0
- package/src/managers/files.ts +182 -0
- package/src/managers/functionRuns.ts +229 -0
- package/src/managers/functions.ts +171 -0
- package/src/managers/orchestrationRuns.ts +122 -0
- package/src/managers/orchestrations.ts +297 -0
- package/src/managers/query.ts +199 -0
- package/src/managers/records.ts +186 -0
- package/src/managers/smartQueries.ts +374 -0
- package/src/managers/structures.ts +205 -0
- package/src/managers/triggers.ts +349 -0
- package/src/managers/validation.ts +303 -0
- package/src/managers/webhookSubscriptions.ts +206 -0
- package/src/realtime/manager.ts +292 -0
- package/src/types/allowedDomains.ts +29 -0
- package/src/types/auth.ts +83 -0
- package/src/types/common.ts +57 -0
- package/src/types/compute.ts +145 -0
- package/src/types/insights.ts +113 -0
- package/src/types/orchestrations.ts +460 -0
- package/src/types/realtime.ts +403 -0
- package/src/types/records.ts +261 -0
- package/src/types/search.ts +44 -0
- package/src/types/smartQueries.ts +303 -0
- package/src/types/structures.ts +203 -0
- package/src/types/triggers.ts +122 -0
- package/src/types/validation.ts +167 -0
- package/src/types/webhooks.ts +114 -0
- package/src/urls.ts +33 -0
- package/dist/query-types.d.ts +0 -187
- package/dist/query-types.js +0 -137
- package/dist/scripts/smoke-types.d.ts +0 -12
- package/dist/scripts/smoke-types.js +0 -102
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// =====================================================
|
|
2
|
+
// Validation Manager (Data Quality)
|
|
3
|
+
// =====================================================
|
|
4
|
+
|
|
5
|
+
import type { Method } from 'axios';
|
|
6
|
+
import type { ApiResponse } from '../types/common';
|
|
7
|
+
import type {
|
|
8
|
+
BatchScanResult,
|
|
9
|
+
TriggerScanOptions,
|
|
10
|
+
WaitForScanOptions,
|
|
11
|
+
ValidationSuggestion,
|
|
12
|
+
ValidationSuggestionStatus,
|
|
13
|
+
ListValidationSuggestionsOptions,
|
|
14
|
+
AcceptSuggestionResult,
|
|
15
|
+
BulkOperationResult,
|
|
16
|
+
ValidationSummary,
|
|
17
|
+
} from '../types/validation';
|
|
18
|
+
import {
|
|
19
|
+
getValidationScanApiPath,
|
|
20
|
+
getValidationSuggestionsApiPath,
|
|
21
|
+
getValidationRecordSuggestionsApiPath,
|
|
22
|
+
getValidationSuggestionAcceptApiPath,
|
|
23
|
+
getValidationSuggestionRejectApiPath,
|
|
24
|
+
getValidationBulkAcceptApiPath,
|
|
25
|
+
getValidationBulkRejectApiPath,
|
|
26
|
+
getValidationSummaryApiPath,
|
|
27
|
+
getValidationPendingCountApiPath,
|
|
28
|
+
} from '../internal/paths';
|
|
29
|
+
|
|
30
|
+
// =====================================================
|
|
31
|
+
// Validation Manager (Data Quality)
|
|
32
|
+
// =====================================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* ValidationManager provides methods for AI-powered data quality validation.
|
|
36
|
+
* Access via `client.validation`.
|
|
37
|
+
*
|
|
38
|
+
* Features:
|
|
39
|
+
* - Trigger batch validation scans on structures
|
|
40
|
+
* - List and manage validation suggestions (typos, format issues, duplicates)
|
|
41
|
+
* - Accept or reject suggestions to fix data
|
|
42
|
+
* - Get validation summaries and statistics
|
|
43
|
+
*
|
|
44
|
+
* Usage:
|
|
45
|
+
* ```ts
|
|
46
|
+
* // Trigger a batch scan
|
|
47
|
+
* const batch = await client.validation.triggerScan('orders');
|
|
48
|
+
* console.log('Scan started:', batch.data.batchId);
|
|
49
|
+
*
|
|
50
|
+
* // Wait for completion
|
|
51
|
+
* const result = await client.validation.waitForScan(batch.data.batchId);
|
|
52
|
+
*
|
|
53
|
+
* // List pending suggestions
|
|
54
|
+
* const suggestions = await client.validation.listSuggestions({ status: 'pending' });
|
|
55
|
+
*
|
|
56
|
+
* // Accept a suggestion (applies the fix)
|
|
57
|
+
* await client.validation.accept('suggestion-id');
|
|
58
|
+
*
|
|
59
|
+
* // Bulk accept high-confidence suggestions
|
|
60
|
+
* const highConfidence = suggestions.data.filter(s => s.confidence >= 0.95);
|
|
61
|
+
* await client.validation.bulkAccept(highConfidence.map(s => s.id));
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export class ValidationManager {
|
|
65
|
+
private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
|
|
66
|
+
private workspaceId: string;
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
workspaceId: string,
|
|
70
|
+
requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
|
|
71
|
+
) {
|
|
72
|
+
this.workspaceId = workspaceId;
|
|
73
|
+
this.requestFn = requestFn;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Trigger a batch validation scan on a structure.
|
|
78
|
+
*
|
|
79
|
+
* @param structureSlug - The structure's slug to scan
|
|
80
|
+
* @param options - Optional scan configuration
|
|
81
|
+
* @returns The batch scan result with batchId for tracking
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* const batch = await client.validation.triggerScan('orders');
|
|
86
|
+
* console.log('Batch ID:', batch.data.batchId);
|
|
87
|
+
* console.log('Records to scan:', batch.data.total);
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
public triggerScan(
|
|
91
|
+
structureSlug: string,
|
|
92
|
+
options?: TriggerScanOptions
|
|
93
|
+
): Promise<ApiResponse<BatchScanResult>> {
|
|
94
|
+
const path = getValidationScanApiPath(this.workspaceId);
|
|
95
|
+
// Note: workspaceSlug is in URL path, not body
|
|
96
|
+
return this.requestFn<BatchScanResult>('POST', path, {
|
|
97
|
+
structureSlug,
|
|
98
|
+
validationTypes: options?.validationTypes,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get the status of a batch validation scan.
|
|
104
|
+
*
|
|
105
|
+
* @param batchId - The batch scan ID
|
|
106
|
+
* @returns Current scan status and progress
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const status = await client.validation.getScanStatus('batch-id');
|
|
111
|
+
* console.log('Progress:', status.data.processed, '/', status.data.total);
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
public getScanStatus(batchId: string): Promise<ApiResponse<BatchScanResult>> {
|
|
115
|
+
const path = getValidationScanApiPath(this.workspaceId, batchId);
|
|
116
|
+
return this.requestFn<BatchScanResult>('GET', path);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Wait for a batch scan to complete with polling.
|
|
121
|
+
*
|
|
122
|
+
* @param batchId - The batch scan ID
|
|
123
|
+
* @param options - Polling configuration
|
|
124
|
+
* @returns The final scan result
|
|
125
|
+
* @throws Error if scan fails or times out
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* const result = await client.validation.waitForScan('batch-id', {
|
|
130
|
+
* pollInterval: 5000, // 5 seconds
|
|
131
|
+
* timeout: 300000 // 5 minutes
|
|
132
|
+
* });
|
|
133
|
+
* console.log('Scan complete:', result.data.issuesFound, 'issues found');
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
public async waitForScan(
|
|
137
|
+
batchId: string,
|
|
138
|
+
options?: WaitForScanOptions
|
|
139
|
+
): Promise<ApiResponse<BatchScanResult>> {
|
|
140
|
+
const pollInterval = options?.pollInterval ?? 5000;
|
|
141
|
+
const timeout = options?.timeout ?? 300000;
|
|
142
|
+
const startTime = Date.now();
|
|
143
|
+
|
|
144
|
+
while (true) {
|
|
145
|
+
const result = await this.getScanStatus(batchId);
|
|
146
|
+
const status = result.data.status;
|
|
147
|
+
|
|
148
|
+
if (status === 'completed') {
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (status === 'failed') {
|
|
153
|
+
throw new Error(`Scan failed: ${result.data.error || 'Unknown error'}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (Date.now() - startTime > timeout) {
|
|
157
|
+
throw new Error(`Scan timed out after ${timeout}ms`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* List validation suggestions with optional filters.
|
|
166
|
+
*
|
|
167
|
+
* @param options - Filter and pagination options
|
|
168
|
+
* @returns List of validation suggestions
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```ts
|
|
172
|
+
* // List all pending suggestions
|
|
173
|
+
* const pending = await client.validation.listSuggestions({ status: 'pending' });
|
|
174
|
+
*
|
|
175
|
+
* // List high-confidence typo suggestions
|
|
176
|
+
* const typos = await client.validation.listSuggestions({
|
|
177
|
+
* issueType: 'typo',
|
|
178
|
+
* minConfidence: 0.9
|
|
179
|
+
* });
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
public listSuggestions(
|
|
183
|
+
options?: ListValidationSuggestionsOptions
|
|
184
|
+
): Promise<ApiResponse<ValidationSuggestion[]>> {
|
|
185
|
+
const path = getValidationSuggestionsApiPath(this.workspaceId);
|
|
186
|
+
return this.requestFn<ValidationSuggestion[]>('GET', path, null, options);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get a single validation suggestion by ID.
|
|
191
|
+
*
|
|
192
|
+
* @param suggestionId - The suggestion UUID
|
|
193
|
+
* @returns The suggestion details
|
|
194
|
+
*/
|
|
195
|
+
public getSuggestion(suggestionId: string): Promise<ApiResponse<ValidationSuggestion>> {
|
|
196
|
+
const path = getValidationSuggestionsApiPath(this.workspaceId, suggestionId);
|
|
197
|
+
return this.requestFn<ValidationSuggestion>('GET', path);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get all suggestions for a specific record.
|
|
202
|
+
*
|
|
203
|
+
* @param recordId - The record UUID
|
|
204
|
+
* @param status - Optional status filter
|
|
205
|
+
* @returns List of suggestions for the record
|
|
206
|
+
*/
|
|
207
|
+
public getRecordSuggestions(
|
|
208
|
+
recordId: string,
|
|
209
|
+
status?: ValidationSuggestionStatus
|
|
210
|
+
): Promise<ApiResponse<ValidationSuggestion[]>> {
|
|
211
|
+
const path = getValidationRecordSuggestionsApiPath(this.workspaceId, recordId);
|
|
212
|
+
const params = status ? { status } : undefined;
|
|
213
|
+
return this.requestFn<ValidationSuggestion[]>('GET', path, null, params);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Accept a validation suggestion and apply the fix to the record.
|
|
218
|
+
*
|
|
219
|
+
* @param suggestionId - The suggestion UUID
|
|
220
|
+
* @returns Result with updated suggestion and record status
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* const result = await client.validation.accept('suggestion-id');
|
|
225
|
+
* if (result.data.recordUpdated) {
|
|
226
|
+
* console.log('Fix applied successfully');
|
|
227
|
+
* }
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
public accept(suggestionId: string): Promise<ApiResponse<AcceptSuggestionResult>> {
|
|
231
|
+
const path = getValidationSuggestionAcceptApiPath(this.workspaceId, suggestionId);
|
|
232
|
+
return this.requestFn<AcceptSuggestionResult>('POST', path);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Reject a validation suggestion.
|
|
237
|
+
*
|
|
238
|
+
* @param suggestionId - The suggestion UUID
|
|
239
|
+
* @returns The updated suggestion
|
|
240
|
+
*/
|
|
241
|
+
public reject(suggestionId: string): Promise<ApiResponse<ValidationSuggestion>> {
|
|
242
|
+
const path = getValidationSuggestionRejectApiPath(this.workspaceId, suggestionId);
|
|
243
|
+
return this.requestFn<ValidationSuggestion>('POST', path);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Bulk accept multiple suggestions.
|
|
248
|
+
*
|
|
249
|
+
* @param ids - Array of suggestion IDs to accept (max 100)
|
|
250
|
+
* @returns Result with count and any errors
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* const result = await client.validation.bulkAccept(['id1', 'id2', 'id3']);
|
|
255
|
+
* console.log('Accepted:', result.data.count);
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
public bulkAccept(ids: string[]): Promise<ApiResponse<BulkOperationResult>> {
|
|
259
|
+
const path = getValidationBulkAcceptApiPath(this.workspaceId);
|
|
260
|
+
return this.requestFn<BulkOperationResult>('POST', path, { ids });
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Bulk reject multiple suggestions.
|
|
265
|
+
*
|
|
266
|
+
* @param ids - Array of suggestion IDs to reject (max 100)
|
|
267
|
+
* @returns Result with count and any errors
|
|
268
|
+
*/
|
|
269
|
+
public bulkReject(ids: string[]): Promise<ApiResponse<BulkOperationResult>> {
|
|
270
|
+
const path = getValidationBulkRejectApiPath(this.workspaceId);
|
|
271
|
+
return this.requestFn<BulkOperationResult>('POST', path, { ids });
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Get validation summary statistics.
|
|
276
|
+
*
|
|
277
|
+
* @param structureId - Optional structure ID to filter summary
|
|
278
|
+
* @returns Summary of suggestions by status and type
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```ts
|
|
282
|
+
* const summary = await client.validation.getSummary();
|
|
283
|
+
* console.log('Pending:', summary.data.pending);
|
|
284
|
+
* console.log('By type:', summary.data.byIssueType);
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
public getSummary(structureSlug?: string): Promise<ApiResponse<ValidationSummary>> {
|
|
288
|
+
const path = getValidationSummaryApiPath(this.workspaceId);
|
|
289
|
+
const params = structureSlug ? { structureSlug } : undefined;
|
|
290
|
+
return this.requestFn<ValidationSummary>('GET', path, null, params);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Get the count of pending suggestions for a structure.
|
|
295
|
+
*
|
|
296
|
+
* @param structureSlug - The structure slug (recordSlug)
|
|
297
|
+
* @returns Object with pending count
|
|
298
|
+
*/
|
|
299
|
+
public getPendingCount(structureSlug: string): Promise<ApiResponse<{ structureSlug: string; pendingCount: number }>> {
|
|
300
|
+
const path = getValidationPendingCountApiPath(this.workspaceId, structureSlug);
|
|
301
|
+
return this.requestFn<{ structureSlug: string; pendingCount: number }>('GET', path);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// =====================================================
|
|
2
|
+
// Webhook Subscriptions Manager
|
|
3
|
+
// =====================================================
|
|
4
|
+
|
|
5
|
+
import type { Method } from 'axios';
|
|
6
|
+
import type { ApiResponse } from '../types/common';
|
|
7
|
+
import type {
|
|
8
|
+
WebhookSubscription,
|
|
9
|
+
WebhookDelivery,
|
|
10
|
+
WebhookDeliverySummary,
|
|
11
|
+
WebhookDeliveriesListMeta,
|
|
12
|
+
WebhookReplayResponse,
|
|
13
|
+
WebhookCancelResponse,
|
|
14
|
+
CreateWebhookSubscriptionInput,
|
|
15
|
+
UpdateWebhookSubscriptionInput,
|
|
16
|
+
ListWebhookDeliveriesOptions,
|
|
17
|
+
} from '../types/webhooks';
|
|
18
|
+
import {
|
|
19
|
+
getWebhookSubscriptionsApiPath,
|
|
20
|
+
getWebhookSubscriptionRotateSecretApiPath,
|
|
21
|
+
getWebhookSubscriptionDeliveriesApiPath,
|
|
22
|
+
getWebhookDeliveryRetryApiPath,
|
|
23
|
+
getWebhookDeliveryCancelApiPath,
|
|
24
|
+
} from '../internal/paths';
|
|
25
|
+
|
|
26
|
+
// =====================================================
|
|
27
|
+
// Webhook Subscriptions Manager
|
|
28
|
+
// =====================================================
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* WebhookSubscriptionsManager provides methods for managing outbound webhook
|
|
32
|
+
* subscriptions and inspecting delivery history. Access via
|
|
33
|
+
* `centrali.webhookSubscriptions`.
|
|
34
|
+
*
|
|
35
|
+
* Subscriptions listen for record events (`record_created`, `record_updated`,
|
|
36
|
+
* `record_deleted`, `records_bulk_created`) and POST a signed JSON payload to
|
|
37
|
+
* your URL. Payloads are signed with HMAC-SHA256 using the subscription's
|
|
38
|
+
* `whsec_` secret and delivered in the `X-Signature` header.
|
|
39
|
+
*
|
|
40
|
+
* Usage:
|
|
41
|
+
* ```ts
|
|
42
|
+
* // Create a subscription
|
|
43
|
+
* const sub = await centrali.webhookSubscriptions.create({
|
|
44
|
+
* name: 'Orders webhook',
|
|
45
|
+
* url: 'https://my-app.example.com/webhooks/centrali',
|
|
46
|
+
* events: [RecordEvents.CREATED, RecordEvents.UPDATED],
|
|
47
|
+
* recordSlugs: ['orders'],
|
|
48
|
+
* });
|
|
49
|
+
* // The signing secret is returned on create — copy it now, it's not shown again.
|
|
50
|
+
* // `secret` is typed `string | undefined` (reads omit it), so assert here.
|
|
51
|
+
* console.log('Signing secret:', sub.data.secret!);
|
|
52
|
+
*
|
|
53
|
+
* // Rotate the secret (immediate cutover)
|
|
54
|
+
* const rotated = await centrali.webhookSubscriptions.rotateSecret(sub.data.id);
|
|
55
|
+
*
|
|
56
|
+
* // Inspect delivery history
|
|
57
|
+
* const deliveries = await centrali.webhookSubscriptions.deliveries.list(sub.data.id);
|
|
58
|
+
*
|
|
59
|
+
* // Replay a delivery
|
|
60
|
+
* await centrali.webhookSubscriptions.deliveries.retry(deliveryId);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export class WebhookSubscriptionsManager {
|
|
64
|
+
private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
|
|
65
|
+
private workspaceId: string;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Delivery history and replay controls. Deliveries are per-subscription for
|
|
69
|
+
* list/get, but retry/cancel are workspace-scoped — the backend routes
|
|
70
|
+
* those under `/webhook-subscriptions/deliveries/{id}/retry|cancel`, so the
|
|
71
|
+
* subscription ID is not needed to replay or cancel.
|
|
72
|
+
*/
|
|
73
|
+
public readonly deliveries: {
|
|
74
|
+
/**
|
|
75
|
+
* List deliveries for a subscription. Rows omit `requestPayload` and
|
|
76
|
+
* `responseBody` — use `deliveries.get()` to fetch the full record.
|
|
77
|
+
* `result.data` is the array of trimmed rows; `result.meta` carries
|
|
78
|
+
* the pagination counters (`total`, `limit`, `offset`).
|
|
79
|
+
*/
|
|
80
|
+
list: (subscriptionId: string, options?: ListWebhookDeliveriesOptions) => Promise<ApiResponse<WebhookDeliverySummary[]> & { meta?: WebhookDeliveriesListMeta }>;
|
|
81
|
+
/** Get a single delivery including the full payload and response body. */
|
|
82
|
+
get: (subscriptionId: string, deliveryId: string) => Promise<ApiResponse<WebhookDelivery>>;
|
|
83
|
+
/**
|
|
84
|
+
* Replay a previously recorded delivery. Queues a new delivery row
|
|
85
|
+
* pointing at `replayedFrom` the original. Returns the new delivery ID.
|
|
86
|
+
*/
|
|
87
|
+
retry: (deliveryId: string) => Promise<ApiResponse<WebhookReplayResponse>>;
|
|
88
|
+
/**
|
|
89
|
+
* Cancel a delivery that is currently in `retrying` status. Flips the
|
|
90
|
+
* row to `failed` with `lastError = 'Cancelled by user'`.
|
|
91
|
+
*/
|
|
92
|
+
cancel: (deliveryId: string) => Promise<ApiResponse<WebhookCancelResponse>>;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
constructor(
|
|
96
|
+
workspaceId: string,
|
|
97
|
+
requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
|
|
98
|
+
) {
|
|
99
|
+
this.workspaceId = workspaceId;
|
|
100
|
+
this.requestFn = requestFn;
|
|
101
|
+
|
|
102
|
+
const toIso = (v: string | Date | undefined): string | undefined => {
|
|
103
|
+
if (!v) return undefined;
|
|
104
|
+
return v instanceof Date ? v.toISOString() : v;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
this.deliveries = {
|
|
108
|
+
list: (subscriptionId: string, options?: ListWebhookDeliveriesOptions) => {
|
|
109
|
+
const path = getWebhookSubscriptionDeliveriesApiPath(this.workspaceId, subscriptionId);
|
|
110
|
+
const queryParams: Record<string, any> = {};
|
|
111
|
+
if (options?.status) queryParams.status = options.status;
|
|
112
|
+
if (options?.since) queryParams.since = toIso(options.since);
|
|
113
|
+
if (options?.until) queryParams.until = toIso(options.until);
|
|
114
|
+
if (options?.limit !== undefined) queryParams.limit = options.limit;
|
|
115
|
+
if (options?.offset !== undefined) queryParams.offset = options.offset;
|
|
116
|
+
return this.requestFn<WebhookDeliverySummary[]>(
|
|
117
|
+
'GET',
|
|
118
|
+
path,
|
|
119
|
+
null,
|
|
120
|
+
Object.keys(queryParams).length > 0 ? queryParams : undefined
|
|
121
|
+
) as Promise<ApiResponse<WebhookDeliverySummary[]> & { meta?: WebhookDeliveriesListMeta }>;
|
|
122
|
+
},
|
|
123
|
+
get: (subscriptionId: string, deliveryId: string) => {
|
|
124
|
+
const path = getWebhookSubscriptionDeliveriesApiPath(this.workspaceId, subscriptionId, deliveryId);
|
|
125
|
+
return this.requestFn<WebhookDelivery>('GET', path);
|
|
126
|
+
},
|
|
127
|
+
retry: (deliveryId: string) => {
|
|
128
|
+
const path = getWebhookDeliveryRetryApiPath(this.workspaceId, deliveryId);
|
|
129
|
+
return this.requestFn<WebhookReplayResponse>('POST', path);
|
|
130
|
+
},
|
|
131
|
+
cancel: (deliveryId: string) => {
|
|
132
|
+
const path = getWebhookDeliveryCancelApiPath(this.workspaceId, deliveryId);
|
|
133
|
+
return this.requestFn<WebhookCancelResponse>('POST', path);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* List all webhook subscriptions in the workspace.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* const subs = await centrali.webhookSubscriptions.list();
|
|
144
|
+
* for (const sub of subs.data) console.log(sub.name, sub.url);
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
public list(): Promise<ApiResponse<WebhookSubscription[]>> {
|
|
148
|
+
const path = getWebhookSubscriptionsApiPath(this.workspaceId);
|
|
149
|
+
return this.requestFn<WebhookSubscription[]>('GET', path);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get a webhook subscription by ID.
|
|
154
|
+
* @param subscriptionId - The subscription UUID
|
|
155
|
+
*/
|
|
156
|
+
public get(subscriptionId: string): Promise<ApiResponse<WebhookSubscription>> {
|
|
157
|
+
const path = getWebhookSubscriptionsApiPath(this.workspaceId, subscriptionId);
|
|
158
|
+
return this.requestFn<WebhookSubscription>('GET', path);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Create a webhook subscription. The response `secret` field is only
|
|
163
|
+
* populated on this call (and on `rotateSecret`) — copy it immediately;
|
|
164
|
+
* subsequent `get`/`list` responses do not return the secret.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* const sub = await centrali.webhookSubscriptions.create({
|
|
169
|
+
* name: 'Order notifications',
|
|
170
|
+
* url: 'https://api.example.com/hooks/centrali',
|
|
171
|
+
* events: [RecordEvents.CREATED, RecordEvents.UPDATED],
|
|
172
|
+
* recordSlugs: ['orders'],
|
|
173
|
+
* });
|
|
174
|
+
* const signingSecret = sub.data.secret; // copy once — not returned on reads
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
public create(input: CreateWebhookSubscriptionInput): Promise<ApiResponse<WebhookSubscription>> {
|
|
178
|
+
const path = getWebhookSubscriptionsApiPath(this.workspaceId);
|
|
179
|
+
return this.requestFn<WebhookSubscription>('POST', path, input);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Update fields on a webhook subscription. The signing secret is managed
|
|
184
|
+
* by the server — use `rotateSecret()` to regenerate it.
|
|
185
|
+
*/
|
|
186
|
+
public update(subscriptionId: string, patch: UpdateWebhookSubscriptionInput): Promise<ApiResponse<WebhookSubscription>> {
|
|
187
|
+
const path = getWebhookSubscriptionsApiPath(this.workspaceId, subscriptionId);
|
|
188
|
+
return this.requestFn<WebhookSubscription>('PATCH', path, patch);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Delete a webhook subscription. Existing delivery history is retained. */
|
|
192
|
+
public delete(subscriptionId: string): Promise<ApiResponse<void>> {
|
|
193
|
+
const path = getWebhookSubscriptionsApiPath(this.workspaceId, subscriptionId);
|
|
194
|
+
return this.requestFn<void>('DELETE', path);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Rotate the signing secret. Immediate cutover — the previous secret stops
|
|
199
|
+
* signing on the next dispatch. The response includes the new secret;
|
|
200
|
+
* capture it before closing the response.
|
|
201
|
+
*/
|
|
202
|
+
public rotateSecret(subscriptionId: string): Promise<ApiResponse<WebhookSubscription>> {
|
|
203
|
+
const path = getWebhookSubscriptionRotateSecretApiPath(this.workspaceId, subscriptionId);
|
|
204
|
+
return this.requestFn<WebhookSubscription>('POST', path);
|
|
205
|
+
}
|
|
206
|
+
}
|