@vorionsys/cognigate 1.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 +270 -0
- package/dist/index.cjs +515 -0
- package/dist/index.d.cts +506 -0
- package/dist/index.js +477 -0
- package/package.json +54 -0
- package/src/__tests__/client.test.ts +162 -0
- package/src/client.ts +421 -0
- package/src/index.ts +76 -0
- package/src/types.ts +272 -0
- package/src/webhooks.ts +146 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +14 -0
package/src/client.ts
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cognigate TypeScript SDK - Client
|
|
3
|
+
*
|
|
4
|
+
* Main client class for interacting with the Cognigate API
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
CognigateConfig,
|
|
9
|
+
TrustStatus,
|
|
10
|
+
GovernanceResult,
|
|
11
|
+
Intent,
|
|
12
|
+
IntentParseResult,
|
|
13
|
+
ProofRecord,
|
|
14
|
+
ProofChainStats,
|
|
15
|
+
Agent,
|
|
16
|
+
CreateAgentRequest,
|
|
17
|
+
UpdateAgentRequest,
|
|
18
|
+
PaginatedResponse,
|
|
19
|
+
TrustTier,
|
|
20
|
+
TIER_THRESHOLDS,
|
|
21
|
+
TrustStatusSchema,
|
|
22
|
+
GovernanceResultSchema,
|
|
23
|
+
ProofRecordSchema,
|
|
24
|
+
AgentSchema,
|
|
25
|
+
} from './types.js';
|
|
26
|
+
|
|
27
|
+
const DEFAULT_BASE_URL = 'https://cognigate.dev/v1';
|
|
28
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
29
|
+
const DEFAULT_RETRIES = 3;
|
|
30
|
+
|
|
31
|
+
export class CognigateError extends Error {
|
|
32
|
+
constructor(
|
|
33
|
+
message: string,
|
|
34
|
+
public code: string,
|
|
35
|
+
public status?: number,
|
|
36
|
+
public details?: Record<string, unknown>
|
|
37
|
+
) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = 'CognigateError';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class Cognigate {
|
|
44
|
+
private readonly config: Required<Omit<CognigateConfig, 'webhookSecret'>> & { webhookSecret?: string };
|
|
45
|
+
public readonly agents: AgentsClient;
|
|
46
|
+
public readonly trust: TrustClient;
|
|
47
|
+
public readonly governance: GovernanceClient;
|
|
48
|
+
public readonly proofs: ProofsClient;
|
|
49
|
+
|
|
50
|
+
constructor(config: CognigateConfig) {
|
|
51
|
+
if (!config.apiKey) {
|
|
52
|
+
throw new CognigateError('API key is required', 'MISSING_API_KEY');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.config = {
|
|
56
|
+
apiKey: config.apiKey,
|
|
57
|
+
baseUrl: config.baseUrl || DEFAULT_BASE_URL,
|
|
58
|
+
timeout: config.timeout || DEFAULT_TIMEOUT,
|
|
59
|
+
retries: config.retries || DEFAULT_RETRIES,
|
|
60
|
+
debug: config.debug || false,
|
|
61
|
+
webhookSecret: config.webhookSecret,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Initialize sub-clients
|
|
65
|
+
this.agents = new AgentsClient(this);
|
|
66
|
+
this.trust = new TrustClient(this);
|
|
67
|
+
this.governance = new GovernanceClient(this);
|
|
68
|
+
this.proofs = new ProofsClient(this);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Make an authenticated request to the Cognigate API
|
|
73
|
+
*/
|
|
74
|
+
async request<T>(
|
|
75
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
|
|
76
|
+
path: string,
|
|
77
|
+
body?: unknown
|
|
78
|
+
): Promise<T> {
|
|
79
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
80
|
+
|
|
81
|
+
const headers: Record<string, string> = {
|
|
82
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
83
|
+
'Content-Type': 'application/json',
|
|
84
|
+
'X-SDK-Version': '1.0.0',
|
|
85
|
+
'X-SDK-Language': 'typescript',
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
let lastError: Error | null = null;
|
|
89
|
+
|
|
90
|
+
for (let attempt = 0; attempt < this.config.retries; attempt++) {
|
|
91
|
+
try {
|
|
92
|
+
const controller = new AbortController();
|
|
93
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
94
|
+
|
|
95
|
+
const response = await fetch(url, {
|
|
96
|
+
method,
|
|
97
|
+
headers,
|
|
98
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
99
|
+
signal: controller.signal,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
clearTimeout(timeoutId);
|
|
103
|
+
|
|
104
|
+
if (this.config.debug) {
|
|
105
|
+
console.log(`[Cognigate] ${method} ${path} -> ${response.status}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;
|
|
110
|
+
throw new CognigateError(
|
|
111
|
+
(errorData.message as string) || `Request failed with status ${response.status}`,
|
|
112
|
+
(errorData.code as string) || 'REQUEST_FAILED',
|
|
113
|
+
response.status,
|
|
114
|
+
errorData.details as Record<string, unknown> | undefined
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const data = await response.json();
|
|
119
|
+
return data as T;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
lastError = error as Error;
|
|
122
|
+
|
|
123
|
+
if (error instanceof CognigateError && error.status && error.status < 500) {
|
|
124
|
+
throw error; // Don't retry client errors
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (attempt < this.config.retries - 1) {
|
|
128
|
+
const delay = Math.pow(2, attempt) * 1000;
|
|
129
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
throw lastError || new CognigateError('Request failed', 'UNKNOWN_ERROR');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Check API health
|
|
139
|
+
*/
|
|
140
|
+
async health(): Promise<{ status: string; version: string; timestamp: Date }> {
|
|
141
|
+
return this.request('GET', '/health');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get tier from trust score
|
|
146
|
+
*/
|
|
147
|
+
static getTierFromScore(score: number): TrustTier {
|
|
148
|
+
if (score >= 950) return TrustTier.T7_AUTONOMOUS;
|
|
149
|
+
if (score >= 876) return TrustTier.T6_CERTIFIED;
|
|
150
|
+
if (score >= 800) return TrustTier.T5_TRUSTED;
|
|
151
|
+
if (score >= 650) return TrustTier.T4_OPERATIONAL;
|
|
152
|
+
if (score >= 500) return TrustTier.T3_VERIFIED;
|
|
153
|
+
if (score >= 350) return TrustTier.T2_PROVISIONAL;
|
|
154
|
+
if (score >= 200) return TrustTier.T1_OBSERVED;
|
|
155
|
+
return TrustTier.T0_SANDBOX;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get tier name
|
|
160
|
+
*/
|
|
161
|
+
static getTierName(tier: TrustTier): string {
|
|
162
|
+
return TIER_THRESHOLDS[tier].name;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Get tier thresholds
|
|
167
|
+
*/
|
|
168
|
+
static getTierThresholds(tier: TrustTier): { min: number; max: number; name: string } {
|
|
169
|
+
return TIER_THRESHOLDS[tier];
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// =============================================================================
|
|
174
|
+
// AGENTS CLIENT
|
|
175
|
+
// =============================================================================
|
|
176
|
+
|
|
177
|
+
class AgentsClient {
|
|
178
|
+
constructor(private client: Cognigate) {}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* List all agents
|
|
182
|
+
*/
|
|
183
|
+
async list(params?: {
|
|
184
|
+
page?: number;
|
|
185
|
+
pageSize?: number;
|
|
186
|
+
status?: 'ACTIVE' | 'PAUSED' | 'SUSPENDED';
|
|
187
|
+
}): Promise<PaginatedResponse<Agent>> {
|
|
188
|
+
const query = new URLSearchParams();
|
|
189
|
+
if (params?.page) query.set('page', params.page.toString());
|
|
190
|
+
if (params?.pageSize) query.set('pageSize', params.pageSize.toString());
|
|
191
|
+
if (params?.status) query.set('status', params.status);
|
|
192
|
+
|
|
193
|
+
const queryString = query.toString();
|
|
194
|
+
const path = `/agents${queryString ? `?${queryString}` : ''}`;
|
|
195
|
+
|
|
196
|
+
return this.client.request('GET', path);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Get a specific agent
|
|
201
|
+
*/
|
|
202
|
+
async get(agentId: string): Promise<Agent> {
|
|
203
|
+
const response = await this.client.request<Agent>('GET', `/agents/${agentId}`);
|
|
204
|
+
return AgentSchema.parse(response);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Create a new agent
|
|
209
|
+
*/
|
|
210
|
+
async create(data: CreateAgentRequest): Promise<Agent> {
|
|
211
|
+
const response = await this.client.request<Agent>('POST', '/agents', data);
|
|
212
|
+
return AgentSchema.parse(response);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Update an agent
|
|
217
|
+
*/
|
|
218
|
+
async update(agentId: string, data: UpdateAgentRequest): Promise<Agent> {
|
|
219
|
+
const response = await this.client.request<Agent>('PATCH', `/agents/${agentId}`, data);
|
|
220
|
+
return AgentSchema.parse(response);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Delete an agent
|
|
225
|
+
*/
|
|
226
|
+
async delete(agentId: string): Promise<void> {
|
|
227
|
+
await this.client.request('DELETE', `/agents/${agentId}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Pause an agent
|
|
232
|
+
*/
|
|
233
|
+
async pause(agentId: string): Promise<Agent> {
|
|
234
|
+
return this.update(agentId, { status: 'PAUSED' });
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Resume an agent
|
|
239
|
+
*/
|
|
240
|
+
async resume(agentId: string): Promise<Agent> {
|
|
241
|
+
return this.update(agentId, { status: 'ACTIVE' });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// =============================================================================
|
|
246
|
+
// TRUST CLIENT
|
|
247
|
+
// =============================================================================
|
|
248
|
+
|
|
249
|
+
class TrustClient {
|
|
250
|
+
constructor(private client: Cognigate) {}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get trust status for an entity
|
|
254
|
+
*/
|
|
255
|
+
async getStatus(entityId: string): Promise<TrustStatus> {
|
|
256
|
+
const response = await this.client.request<TrustStatus>('GET', `/trust/${entityId}`);
|
|
257
|
+
return TrustStatusSchema.parse(response);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Get trust history
|
|
262
|
+
*/
|
|
263
|
+
async getHistory(
|
|
264
|
+
entityId: string,
|
|
265
|
+
params?: { from?: Date; to?: Date; limit?: number }
|
|
266
|
+
): Promise<Array<{ score: number; tier: TrustTier; timestamp: Date }>> {
|
|
267
|
+
const query = new URLSearchParams();
|
|
268
|
+
if (params?.from) query.set('from', params.from.toISOString());
|
|
269
|
+
if (params?.to) query.set('to', params.to.toISOString());
|
|
270
|
+
if (params?.limit) query.set('limit', params.limit.toString());
|
|
271
|
+
|
|
272
|
+
const queryString = query.toString();
|
|
273
|
+
const path = `/trust/${entityId}/history${queryString ? `?${queryString}` : ''}`;
|
|
274
|
+
|
|
275
|
+
return this.client.request('GET', path);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Submit an outcome to update trust score
|
|
280
|
+
*/
|
|
281
|
+
async submitOutcome(
|
|
282
|
+
entityId: string,
|
|
283
|
+
proofId: string,
|
|
284
|
+
outcome: {
|
|
285
|
+
success: boolean;
|
|
286
|
+
metrics?: Record<string, number>;
|
|
287
|
+
notes?: string;
|
|
288
|
+
}
|
|
289
|
+
): Promise<TrustStatus> {
|
|
290
|
+
const response = await this.client.request<TrustStatus>(
|
|
291
|
+
'POST',
|
|
292
|
+
`/trust/${entityId}/outcome`,
|
|
293
|
+
{ proofId, ...outcome }
|
|
294
|
+
);
|
|
295
|
+
return TrustStatusSchema.parse(response);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// =============================================================================
|
|
300
|
+
// GOVERNANCE CLIENT
|
|
301
|
+
// =============================================================================
|
|
302
|
+
|
|
303
|
+
class GovernanceClient {
|
|
304
|
+
constructor(private client: Cognigate) {}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Parse user intent into structured format
|
|
308
|
+
*/
|
|
309
|
+
async parseIntent(entityId: string, rawInput: string): Promise<IntentParseResult> {
|
|
310
|
+
return this.client.request('POST', '/governance/parse', {
|
|
311
|
+
entityId,
|
|
312
|
+
rawInput,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Enforce governance rules on an intent
|
|
318
|
+
*/
|
|
319
|
+
async enforce(intent: Intent): Promise<GovernanceResult> {
|
|
320
|
+
const response = await this.client.request<GovernanceResult>(
|
|
321
|
+
'POST',
|
|
322
|
+
'/governance/enforce',
|
|
323
|
+
intent
|
|
324
|
+
);
|
|
325
|
+
return GovernanceResultSchema.parse(response);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Convenience method: parse and enforce in one call
|
|
330
|
+
*/
|
|
331
|
+
async evaluate(entityId: string, rawInput: string): Promise<{
|
|
332
|
+
intent: Intent;
|
|
333
|
+
result: GovernanceResult;
|
|
334
|
+
}> {
|
|
335
|
+
const parseResult = await this.parseIntent(entityId, rawInput);
|
|
336
|
+
const result = await this.enforce(parseResult.intent);
|
|
337
|
+
return {
|
|
338
|
+
intent: parseResult.intent,
|
|
339
|
+
result,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Check if an action is allowed without creating a proof record
|
|
345
|
+
*/
|
|
346
|
+
async canPerform(
|
|
347
|
+
entityId: string,
|
|
348
|
+
action: string,
|
|
349
|
+
capabilities: string[]
|
|
350
|
+
): Promise<{ allowed: boolean; reason: string }> {
|
|
351
|
+
return this.client.request('POST', '/governance/check', {
|
|
352
|
+
entityId,
|
|
353
|
+
action,
|
|
354
|
+
capabilities,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// =============================================================================
|
|
360
|
+
// PROOFS CLIENT
|
|
361
|
+
// =============================================================================
|
|
362
|
+
|
|
363
|
+
class ProofsClient {
|
|
364
|
+
constructor(private client: Cognigate) {}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Get a specific proof record
|
|
368
|
+
*/
|
|
369
|
+
async get(proofId: string): Promise<ProofRecord> {
|
|
370
|
+
const response = await this.client.request<ProofRecord>('GET', `/proofs/${proofId}`);
|
|
371
|
+
return ProofRecordSchema.parse(response);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* List proof records for an entity
|
|
376
|
+
*/
|
|
377
|
+
async list(
|
|
378
|
+
entityId: string,
|
|
379
|
+
params?: {
|
|
380
|
+
page?: number;
|
|
381
|
+
pageSize?: number;
|
|
382
|
+
from?: Date;
|
|
383
|
+
to?: Date;
|
|
384
|
+
outcome?: 'SUCCESS' | 'FAILURE' | 'PARTIAL';
|
|
385
|
+
}
|
|
386
|
+
): Promise<PaginatedResponse<ProofRecord>> {
|
|
387
|
+
const query = new URLSearchParams();
|
|
388
|
+
query.set('entityId', entityId);
|
|
389
|
+
if (params?.page) query.set('page', params.page.toString());
|
|
390
|
+
if (params?.pageSize) query.set('pageSize', params.pageSize.toString());
|
|
391
|
+
if (params?.from) query.set('from', params.from.toISOString());
|
|
392
|
+
if (params?.to) query.set('to', params.to.toISOString());
|
|
393
|
+
if (params?.outcome) query.set('outcome', params.outcome);
|
|
394
|
+
|
|
395
|
+
return this.client.request('GET', `/proofs?${query.toString()}`);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Get proof chain statistics
|
|
400
|
+
*/
|
|
401
|
+
async getStats(entityId: string): Promise<ProofChainStats> {
|
|
402
|
+
return this.client.request('GET', `/proofs/stats/${entityId}`);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Verify proof chain integrity
|
|
407
|
+
*/
|
|
408
|
+
async verify(entityId: string): Promise<{
|
|
409
|
+
valid: boolean;
|
|
410
|
+
errors: string[];
|
|
411
|
+
lastVerified: Date;
|
|
412
|
+
}> {
|
|
413
|
+
return this.client.request('POST', `/proofs/verify/${entityId}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// =============================================================================
|
|
418
|
+
// EXPORTS
|
|
419
|
+
// =============================================================================
|
|
420
|
+
|
|
421
|
+
export { AgentsClient, TrustClient, GovernanceClient, ProofsClient };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cognigate TypeScript SDK
|
|
3
|
+
*
|
|
4
|
+
* Official SDK for the Cognigate AI Governance API
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
* @module @vorionsys/cognigate
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { Cognigate } from '@vorion/cognigate';
|
|
12
|
+
*
|
|
13
|
+
* const client = new Cognigate({ apiKey: 'your-api-key' });
|
|
14
|
+
*
|
|
15
|
+
* // Get trust status for an agent
|
|
16
|
+
* const status = await client.trust.getStatus('agent-123');
|
|
17
|
+
* console.log(`Trust Score: ${status.trustScore}, Tier: ${status.tierName}`);
|
|
18
|
+
*
|
|
19
|
+
* // Evaluate an action through governance
|
|
20
|
+
* const { intent, result } = await client.governance.evaluate(
|
|
21
|
+
* 'agent-123',
|
|
22
|
+
* 'Read customer data from database'
|
|
23
|
+
* );
|
|
24
|
+
*
|
|
25
|
+
* if (result.decision === 'ALLOW') {
|
|
26
|
+
* // Proceed with action
|
|
27
|
+
* } else {
|
|
28
|
+
* console.log('Blocked:', result.reasoning);
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
// Main client
|
|
34
|
+
export { Cognigate, CognigateError } from './client.js';
|
|
35
|
+
export type { AgentsClient, TrustClient, GovernanceClient, ProofsClient } from './client.js';
|
|
36
|
+
|
|
37
|
+
// Types
|
|
38
|
+
export {
|
|
39
|
+
TrustTier,
|
|
40
|
+
TIER_THRESHOLDS,
|
|
41
|
+
type GovernanceDecision,
|
|
42
|
+
type GovernanceResult,
|
|
43
|
+
type Intent,
|
|
44
|
+
type IntentParseResult,
|
|
45
|
+
type TrustStatus,
|
|
46
|
+
type ProofRecord,
|
|
47
|
+
type ProofChainStats,
|
|
48
|
+
type Agent,
|
|
49
|
+
type CreateAgentRequest,
|
|
50
|
+
type UpdateAgentRequest,
|
|
51
|
+
type ApiResponse,
|
|
52
|
+
type ApiError,
|
|
53
|
+
type PaginatedResponse,
|
|
54
|
+
type WebhookEvent,
|
|
55
|
+
type WebhookEventType,
|
|
56
|
+
type CognigateConfig,
|
|
57
|
+
} from './types.js';
|
|
58
|
+
|
|
59
|
+
// Schemas for runtime validation
|
|
60
|
+
export {
|
|
61
|
+
TrustStatusSchema,
|
|
62
|
+
GovernanceResultSchema,
|
|
63
|
+
ProofRecordSchema,
|
|
64
|
+
AgentSchema,
|
|
65
|
+
} from './types.js';
|
|
66
|
+
|
|
67
|
+
// Webhooks
|
|
68
|
+
export {
|
|
69
|
+
verifyWebhookSignature,
|
|
70
|
+
parseWebhookPayload,
|
|
71
|
+
WebhookRouter,
|
|
72
|
+
type WebhookHandler,
|
|
73
|
+
} from './webhooks.js';
|
|
74
|
+
|
|
75
|
+
// Re-export zod for convenience
|
|
76
|
+
export { z } from 'zod';
|