@thinkhive/sdk 3.1.1 → 4.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/MIGRATION.md +83 -12
- package/README.md +279 -128
- package/dist/api/agents.d.ts +169 -0
- package/dist/api/agents.js +185 -0
- package/dist/api/apiKeys.d.ts +252 -0
- package/dist/api/apiKeys.js +298 -0
- package/dist/api/business-metrics.d.ts +188 -0
- package/dist/api/business-metrics.js +213 -0
- package/dist/api/calibration.d.ts +0 -62
- package/dist/api/calibration.js +5 -48
- package/dist/api/claims.js +10 -7
- package/dist/api/conversation-eval.d.ts +200 -0
- package/dist/api/conversation-eval.js +235 -0
- package/dist/api/deterministic-graders.d.ts +205 -0
- package/dist/api/deterministic-graders.js +191 -0
- package/dist/api/eval-health.d.ts +250 -0
- package/dist/api/eval-health.js +224 -0
- package/dist/api/human-review.d.ts +275 -0
- package/dist/api/human-review.js +236 -0
- package/dist/api/nondeterminism.d.ts +300 -0
- package/dist/api/nondeterminism.js +250 -0
- package/dist/api/quality-metrics.d.ts +303 -0
- package/dist/api/quality-metrics.js +198 -0
- package/dist/api/roi-analytics.d.ts +263 -0
- package/dist/api/roi-analytics.js +204 -0
- package/dist/api/runs.js +12 -6
- package/dist/api/transcript-patterns.d.ts +204 -0
- package/dist/api/transcript-patterns.js +227 -0
- package/dist/core/client.d.ts +83 -9
- package/dist/core/client.js +229 -34
- package/dist/core/config.d.ts +2 -3
- package/dist/core/config.js +3 -4
- package/dist/core/types.d.ts +57 -4
- package/dist/core/types.js +1 -1
- package/dist/index.d.ts +429 -76
- package/dist/index.js +262 -42
- package/package.json +2 -2
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ThinkHive SDK - API Keys Management
|
|
4
|
+
*
|
|
5
|
+
* Create and manage scoped API keys with:
|
|
6
|
+
* - Permission control (read/write/delete)
|
|
7
|
+
* - Agent-level scoping (allowedAgentIds)
|
|
8
|
+
* - Environment separation (production/staging/development)
|
|
9
|
+
* - IP whitelisting (allowedIps)
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { apiKeys } from 'thinkhive-js';
|
|
14
|
+
*
|
|
15
|
+
* // Create a read-only key for monitoring
|
|
16
|
+
* const readOnlyKey = await apiKeys.create({
|
|
17
|
+
* name: 'Monitoring Key',
|
|
18
|
+
* scopeType: 'readonly'
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Create a key scoped to specific agents
|
|
22
|
+
* const agentKey = await apiKeys.create({
|
|
23
|
+
* name: 'Agent A Key',
|
|
24
|
+
* allowedAgentIds: ['agent-a-id', 'agent-b-id'],
|
|
25
|
+
* permissions: { read: true, write: true, delete: false }
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // Create a staging environment key
|
|
29
|
+
* const stagingKey = await apiKeys.create({
|
|
30
|
+
* name: 'Staging Key',
|
|
31
|
+
* environment: 'staging',
|
|
32
|
+
* allowedIps: ['10.0.0.1', '10.0.0.2']
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.apiKeys = void 0;
|
|
38
|
+
exports.create = create;
|
|
39
|
+
exports.list = list;
|
|
40
|
+
exports.revoke = revoke;
|
|
41
|
+
exports.rotate = rotate;
|
|
42
|
+
exports.test = test;
|
|
43
|
+
exports.hasPermission = hasPermission;
|
|
44
|
+
exports.isExpired = isExpired;
|
|
45
|
+
exports.isValid = isValid;
|
|
46
|
+
exports.getTimeUntilExpiry = getTimeUntilExpiry;
|
|
47
|
+
exports.canAccessAgent = canAccessAgent;
|
|
48
|
+
const client_1 = require("../core/client");
|
|
49
|
+
// ============================================================================
|
|
50
|
+
// API Key Management Functions
|
|
51
|
+
// ============================================================================
|
|
52
|
+
/**
|
|
53
|
+
* Create a new API key with specified permissions and scoping
|
|
54
|
+
*
|
|
55
|
+
* @param options - API key configuration
|
|
56
|
+
* @returns Created key with secret (only returned once!)
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* // Create a production write key
|
|
61
|
+
* const result = await apiKeys.create({
|
|
62
|
+
* name: 'Production SDK Key',
|
|
63
|
+
* permissions: { read: true, write: true, delete: false }
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* // Save the key securely - it won't be shown again!
|
|
67
|
+
* console.log('Save this key:', result.key);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
async function create(options) {
|
|
71
|
+
if (!options.name || options.name.trim().length === 0) {
|
|
72
|
+
throw new client_1.ThinkHiveValidationError('API key name is required', 'name');
|
|
73
|
+
}
|
|
74
|
+
// Validate IP addresses if provided
|
|
75
|
+
if (options.allowedIps) {
|
|
76
|
+
// IPv4 pattern
|
|
77
|
+
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
78
|
+
// IPv6 pattern (supports full and compressed notation like ::1, 2001:db8::1)
|
|
79
|
+
const ipv6Regex = /^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|:(?::[0-9a-fA-F]{1,4}){1,7}|::)$/;
|
|
80
|
+
for (const ip of options.allowedIps) {
|
|
81
|
+
if (!ipv4Regex.test(ip) && !ipv6Regex.test(ip) && ip !== 'localhost') {
|
|
82
|
+
throw new client_1.ThinkHiveValidationError(`Invalid IP address: ${ip}`, 'allowedIps');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const body = {
|
|
87
|
+
name: options.name.trim(),
|
|
88
|
+
};
|
|
89
|
+
if (options.permissions) {
|
|
90
|
+
body.permissions = {
|
|
91
|
+
read: options.permissions.read !== false,
|
|
92
|
+
write: options.permissions.write === true,
|
|
93
|
+
delete: options.permissions.delete === true,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (options.scopeType) {
|
|
97
|
+
body.scopeType = options.scopeType;
|
|
98
|
+
}
|
|
99
|
+
if (options.environment) {
|
|
100
|
+
body.environment = options.environment;
|
|
101
|
+
}
|
|
102
|
+
if (options.allowedAgentIds && options.allowedAgentIds.length > 0) {
|
|
103
|
+
body.allowedAgentIds = options.allowedAgentIds;
|
|
104
|
+
}
|
|
105
|
+
if (options.allowedIps && options.allowedIps.length > 0) {
|
|
106
|
+
body.allowedIps = options.allowedIps;
|
|
107
|
+
}
|
|
108
|
+
if (options.expiresAt) {
|
|
109
|
+
body.expiresAt = options.expiresAt.toISOString();
|
|
110
|
+
}
|
|
111
|
+
return (0, client_1.apiRequest)('/api-keys', {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
body,
|
|
114
|
+
apiVersion: 'v2',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* List all API keys for the authenticated company
|
|
119
|
+
*
|
|
120
|
+
* @returns Array of API keys (without secrets)
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const keys = await apiKeys.list();
|
|
125
|
+
* console.log(`Found ${keys.length} API keys`);
|
|
126
|
+
*
|
|
127
|
+
* // Filter by environment
|
|
128
|
+
* const prodKeys = keys.filter(k => k.environment === 'production');
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
async function list() {
|
|
132
|
+
return (0, client_1.apiRequest)('/api-keys', {
|
|
133
|
+
method: 'GET',
|
|
134
|
+
apiVersion: 'v2',
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Revoke (deactivate) an API key
|
|
139
|
+
*
|
|
140
|
+
* @param keyId - ID of the key to revoke
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* // Revoke a compromised key
|
|
145
|
+
* await apiKeys.revoke('key-id-to-revoke');
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
async function revoke(keyId) {
|
|
149
|
+
if (!keyId) {
|
|
150
|
+
throw new client_1.ThinkHiveValidationError('Key ID is required', 'keyId');
|
|
151
|
+
}
|
|
152
|
+
await (0, client_1.apiRequest)(`/api-keys/${keyId}`, {
|
|
153
|
+
method: 'DELETE',
|
|
154
|
+
apiVersion: 'v2',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Rotate an API key (revoke old, create new with same config)
|
|
159
|
+
*
|
|
160
|
+
* @param keyId - ID of the key to rotate
|
|
161
|
+
* @param options - Optional overrides for the new key
|
|
162
|
+
* @returns New key with secret
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // Rotate a key periodically
|
|
167
|
+
* const existingKeys = await apiKeys.list();
|
|
168
|
+
* const oldKey = existingKeys.find(k => k.name === 'Production Key');
|
|
169
|
+
*
|
|
170
|
+
* if (oldKey) {
|
|
171
|
+
* const newKey = await apiKeys.rotate(oldKey.id);
|
|
172
|
+
* // Update your systems with newKey.key
|
|
173
|
+
* console.log('New key:', newKey.key);
|
|
174
|
+
* }
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
async function rotate(keyId, options) {
|
|
178
|
+
// Get existing key metadata
|
|
179
|
+
const keys = await list();
|
|
180
|
+
const existingKey = keys.find(k => k.id === keyId);
|
|
181
|
+
if (!existingKey) {
|
|
182
|
+
throw new client_1.ThinkHiveValidationError('API key not found', 'keyId');
|
|
183
|
+
}
|
|
184
|
+
// Create new key with same (or overridden) config
|
|
185
|
+
const newKeyOptions = {
|
|
186
|
+
name: options?.name || existingKey.name,
|
|
187
|
+
scopeType: options?.scopeType || existingKey.scopeType,
|
|
188
|
+
environment: options?.environment || existingKey.environment,
|
|
189
|
+
allowedAgentIds: options?.allowedAgentIds || existingKey.allowedAgentIds || undefined,
|
|
190
|
+
allowedIps: options?.allowedIps || existingKey.allowedIps || undefined,
|
|
191
|
+
};
|
|
192
|
+
// Handle permissions conversion
|
|
193
|
+
if (options?.permissions) {
|
|
194
|
+
newKeyOptions.permissions = options.permissions;
|
|
195
|
+
}
|
|
196
|
+
else if (existingKey.permissions && typeof existingKey.permissions === 'object' && !Array.isArray(existingKey.permissions)) {
|
|
197
|
+
newKeyOptions.permissions = existingKey.permissions;
|
|
198
|
+
}
|
|
199
|
+
// Create new key first (so we don't lose access if creation fails)
|
|
200
|
+
const newKey = await create(newKeyOptions);
|
|
201
|
+
// Revoke old key
|
|
202
|
+
await revoke(keyId);
|
|
203
|
+
return newKey;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Test an API key connection
|
|
207
|
+
*
|
|
208
|
+
* @param apiKey - The full API key value to test
|
|
209
|
+
* @param agentId - Optional agent ID to test with
|
|
210
|
+
* @returns Test result
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* const result = await apiKeys.test('thk_...', 'my-agent-id');
|
|
215
|
+
* if (result.success) {
|
|
216
|
+
* console.log('Key is valid!');
|
|
217
|
+
* }
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
async function test(apiKey, agentId) {
|
|
221
|
+
if (!apiKey) {
|
|
222
|
+
throw new client_1.ThinkHiveValidationError('API key is required', 'apiKey');
|
|
223
|
+
}
|
|
224
|
+
return (0, client_1.apiRequest)('/api-keys/test', {
|
|
225
|
+
method: 'POST',
|
|
226
|
+
body: { apiKey, agentId, createTestTrace: !!agentId },
|
|
227
|
+
apiVersion: 'v2',
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// ============================================================================
|
|
231
|
+
// Utility Functions
|
|
232
|
+
// ============================================================================
|
|
233
|
+
/**
|
|
234
|
+
* Check if an API key has a specific permission
|
|
235
|
+
*/
|
|
236
|
+
function hasPermission(key, permission) {
|
|
237
|
+
// Handle object format
|
|
238
|
+
if (typeof key.permissions === 'object' && !Array.isArray(key.permissions)) {
|
|
239
|
+
return key.permissions[permission] === true;
|
|
240
|
+
}
|
|
241
|
+
// Handle legacy array format
|
|
242
|
+
if (Array.isArray(key.permissions)) {
|
|
243
|
+
return key.permissions.some(p => p.endsWith(`:${permission}`));
|
|
244
|
+
}
|
|
245
|
+
// Default: read allowed, write/delete denied
|
|
246
|
+
return permission === 'read';
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Check if an API key is expired
|
|
250
|
+
*/
|
|
251
|
+
function isExpired(key) {
|
|
252
|
+
if (!key.expiresAt)
|
|
253
|
+
return false;
|
|
254
|
+
return new Date(key.expiresAt) < new Date();
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Check if an API key is valid (active and not expired)
|
|
258
|
+
*/
|
|
259
|
+
function isValid(key) {
|
|
260
|
+
return key.isActive && !isExpired(key);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get time until key expires (in milliseconds)
|
|
264
|
+
* Returns null if key doesn't expire
|
|
265
|
+
*/
|
|
266
|
+
function getTimeUntilExpiry(key) {
|
|
267
|
+
if (!key.expiresAt)
|
|
268
|
+
return null;
|
|
269
|
+
const expiry = new Date(key.expiresAt).getTime();
|
|
270
|
+
const now = Date.now();
|
|
271
|
+
return Math.max(0, expiry - now);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Check if a key can access a specific agent
|
|
275
|
+
*/
|
|
276
|
+
function canAccessAgent(key, agentId) {
|
|
277
|
+
// If no agent restrictions, allow all
|
|
278
|
+
if (!key.allowedAgentIds || key.allowedAgentIds.length === 0) {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
return key.allowedAgentIds.includes(agentId);
|
|
282
|
+
}
|
|
283
|
+
// ============================================================================
|
|
284
|
+
// Export namespace
|
|
285
|
+
// ============================================================================
|
|
286
|
+
exports.apiKeys = {
|
|
287
|
+
create,
|
|
288
|
+
list,
|
|
289
|
+
revoke,
|
|
290
|
+
rotate,
|
|
291
|
+
test,
|
|
292
|
+
hasPermission,
|
|
293
|
+
isExpired,
|
|
294
|
+
isValid,
|
|
295
|
+
getTimeUntilExpiry,
|
|
296
|
+
canAccessAgent,
|
|
297
|
+
};
|
|
298
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpS2V5cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvYXBpS2V5cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWlDRzs7O0FBNElILHdCQXVEQztBQWdCRCxvQkFLQztBQWFELHdCQVNDO0FBc0JELHdCQW1DQztBQWlCRCxvQkFhQztBQVNELHNDQWdCQztBQUtELDhCQUdDO0FBS0QsMEJBRUM7QUFNRCxnREFLQztBQUtELHdDQU1DO0FBallELDJDQUFzRTtBQW9IdEUsK0VBQStFO0FBQy9FLCtCQUErQjtBQUMvQiwrRUFBK0U7QUFFL0U7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUJHO0FBQ0ksS0FBSyxVQUFVLE1BQU0sQ0FBQyxPQUE0QjtJQUN2RCxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN0RCxNQUFNLElBQUksaUNBQXdCLENBQUMsMEJBQTBCLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDekUsQ0FBQztJQUVELG9DQUFvQztJQUNwQyxJQUFJLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUN2QixlQUFlO1FBQ2YsTUFBTSxTQUFTLEdBQUcsNkZBQTZGLENBQUM7UUFDaEgsNkVBQTZFO1FBQzdFLE1BQU0sU0FBUyxHQUFHLHVaQUF1WixDQUFDO1FBQzFhLEtBQUssTUFBTSxFQUFFLElBQUksT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3BDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLEtBQUssV0FBVyxFQUFFLENBQUM7Z0JBQ3JFLE1BQU0sSUFBSSxpQ0FBd0IsQ0FBQyx1QkFBdUIsRUFBRSxFQUFFLEVB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U0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ3pDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQixrQkFBa0IsQ0FBQyxHQUFXO0lBQzVDLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ2hDLE1BQU0sTUFBTSxHQUFHLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNqRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDdkIsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxNQUFNLEdBQUcsR0FBRyxDQUFDLENBQUM7QUFDbkMsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsY0FBYyxDQUFDLEdBQVcsRUFBRSxPQUFlO0lBQ3pELHNDQUFzQztJQUN0QyxJQUFJLENBQUMsR0FBRyxDQUFDLGVBQWUsSUFBSSxHQUFHLENBQUMsZUFBZSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUM3RCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFDRCxPQUFPLEdBQUcsQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQy9DLENBQUM7QUFFRCwrRUFBK0U7QUFDL0UsbUJBQW1CO0FBQ25CLCtFQUErRTtBQUVsRSxRQUFBLE9BQU8sR0FBRztJQUNyQixNQUFNO0lBQ04sSUFBSTtJQUNKLE1BQU07SUFDTixNQUFNO0lBQ04sSUFBSTtJQUNKLGFBQWE7SUFDYixTQUFTO0lBQ1QsT0FBTztJQUNQLGtCQUFrQjtJQUNsQixjQUFjO0NBQ2YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGhpbmtIaXZlIFNESyAtIEFQSSBLZXlzIE1hbmFnZW1lbnRcbiAqXG4gKiBDcmVhdGUgYW5kIG1hbmFnZSBzY29wZWQgQVBJIGtleXMgd2l0aDpcbiAqIC0gUGVybWlzc2lvbiBjb250cm9sIChyZWFkL3dyaXRlL2RlbGV0ZSlcbiAqIC0gQWdlbnQtbGV2ZWwgc2NvcGluZyAoYWxsb3dlZEFnZW50SWRzKVxuICogLSBFbnZpcm9ubWVudCBzZXBhcmF0aW9uIChwcm9kdWN0aW9uL3N0YWdpbmcvZGV2ZWxvcG1lbnQpXG4gKiAtIElQIHdoaXRlbGlzdGluZyAoYWxsb3dlZElwcylcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgYXBpS2V5cyB9IGZyb20gJ3RoaW5raGl2ZS1qcyc7XG4gKlxuICogLy8gQ3JlYXRlIGEgcmVhZC1vbmx5IGtleSBmb3IgbW9uaXRvcmluZ1xuICogY29uc3QgcmVhZE9ubHlLZXkgPSBhd2FpdCBhcGlLZXlzLmNyZWF0ZSh7XG4gKiAgIG5hbWU6ICdNb25pdG9yaW5nIEtleScsXG4gKiAgIHNjb3BlVHlwZTogJ3JlYWRvbmx5J1xuICogfSk7XG4gKlxuICogLy8gQ3JlYXRlIGEga2V5IHNjb3BlZCB0byBzcGVjaWZpYyBhZ2VudHNcbiAqIGNvbnN0IGFnZW50S2V5ID0gYXdhaXQgYXBpS2V5cy5jcmVhdGUoe1xuICogICBuYW1lOiAnQWdlbnQgQSBLZXknLFxuICogICBhbGxvd2VkQWdlbnRJZHM6IFsnYWdlbnQtYS1pZCcsICdhZ2VudC1iLWlkJ10sXG4gKiAgIHBlcm1pc3Npb25zOiB7IHJlYWQ6IHRydWUsIHdyaXRlOiB0cnVlLCBkZWxldGU6IGZhbHNlIH1cbiAqIH0pO1xuICpcbiAqIC8vIENyZWF0ZSBhIHN0YWdpbmcgZW52aXJvbm1lbnQga2V5XG4gKiBjb25zdCBzdGFnaW5nS2V5ID0gYXdhaXQgYXBpS2V5cy5jcmVhdGUoe1xuICogICBuYW1lOiAnU3RhZ2luZyBLZXknLFxuICogICBlbnZpcm9ubWVudDogJ3N0YWdpbmcnLFxuICogICBhbGxvd2VkSXBzOiBbJzEwLjAuMC4xJywgJzEwLjAuMC4yJ11cbiAqIH0pO1xuICogYGBgXG4gKi9cblxuaW1wb3J0IHsgYXBpUmVxdWVzdCwgVGhpbmtIaXZlVmFsaWRhdGlvbkVycm9yIH0gZnJvbSAnLi4vY29yZS9jbGllbnQnO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBUeXBlc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIEFQSSBrZXkgcGVybWlzc2lvbiBjb25maWd1cmF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXBpS2V5UGVybWlzc2lvbnMge1xuICAvKiogQWxsb3cgcmVhZCBvcGVyYXRpb25zIChHRVQgcmVxdWVzdHMsIGxpc3RpbmcsIGV0Yy4pICovXG4gIHJlYWQ6IGJvb2xlYW47XG4gIC8qKiBBbGxvdyB3cml0ZSBvcGVyYXRpb25zIChQT1NULCBQVVQgcmVxdWVzdHMpICovXG4gIHdyaXRlOiBib29sZWFuO1xuICAvKiogQWxsb3cgZGVsZXRlIG9wZXJhdGlvbnMgKERFTEVURSByZXF1ZXN0cykgKi9cbiAgZGVsZXRlOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEFQSSBrZXkgc2NvcGUgdHlwZVxuICogLSBgY29tcGFueWA6IEZ1bGwgYWNjZXNzIHRvIGFsbCBjb21wYW55IGRhdGFcbiAqIC0gYGFnZW50YDogTGltaXRlZCB0byBzcGVjaWZpYyBhZ2VudHMgKHJlcXVpcmVzIGFsbG93ZWRBZ2VudElkcylcbiAqIC0gYHJlYWRvbmx5YDogUmVhZC1vbmx5IGFjY2VzcyByZWdhcmRsZXNzIG9mIG90aGVyIHNldHRpbmdzXG4gKi9cbmV4cG9ydCB0eXBlIFNjb3BlVHlwZSA9ICdjb21wYW55JyB8ICdhZ2VudCcgfCAncmVhZG9ubHknO1xuXG4vKipcbiAqIEFQSSBrZXkgZW52aXJvbm1lbnRcbiAqIC0gYHByb2R1Y3Rpb25gOiBGb3IgcHJvZHVjdGlvbiBzeXN0ZW1zXG4gKiAtIGBzdGFnaW5nYDogRm9yIHN0YWdpbmcvcHJlLXByb2R1Y3Rpb25cbiAqIC0gYGRldmVsb3BtZW50YDogRm9yIGxvY2FsIGRldmVsb3BtZW50XG4gKi9cbmV4cG9ydCB0eXBlIEVudmlyb25tZW50ID0gJ3Byb2R1Y3Rpb24nIHwgJ3N0YWdpbmcnIHwgJ2RldmVsb3BtZW50JztcblxuLyoqXG4gKiBPcHRpb25zIGZvciBjcmVhdGluZyBhbiBBUEkga2V5XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlQXBpS2V5T3B0aW9ucyB7XG4gIC8qKiBEaXNwbGF5IG5hbWUgZm9yIHRoZSBrZXkgKi9cbiAgbmFtZTogc3RyaW5nO1xuXG4gIC8qKiBQZXJtaXNzaW9uIGNvbmZpZ3VyYXRpb24gKGRlZmF1bHRzIHRvIHJlYWQrd3JpdGUpICovXG4gIHBlcm1pc3Npb25zPzogUGFydGlhbDxBcGlLZXlQZXJtaXNzaW9ucz47XG5cbiAgLyoqXG4gICAqIFJlc3RyaWN0IGtleSB0byBzcGVjaWZpYyBhZ2VudCBJRHNcbiAgICogV2hlbiBzZXQsIGtleSBjYW4gb25seSBhY2Nlc3MgdHJhY2VzIGZvciB0aGVzZSBhZ2VudHNcbiAgICovXG4gIGFsbG93ZWRBZ2VudElkcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBTY29wZSB0eXBlIGZvciB0aGUga2V5XG4gICAqIEBkZWZhdWx0ICdjb21wYW55JyBvciAnYWdlbnQnIGlmIGFsbG93ZWRBZ2VudElkcyBpcyBzZXRcbiAgICovXG4gIHNjb3BlVHlwZT86IFNjb3BlVHlwZTtcblxuICAvKipcbiAgICogRW52aXJvbm1lbnQgZm9yIHRoZSBrZXlcbiAgICogQGRlZmF1bHQgJ3Byb2R1Y3Rpb24nXG4gICAqL1xuICBlbnZpcm9ubWVudD86IEVudmlyb25tZW50O1xuXG4gIC8qKlxuICAgKiBSZXN0cmljdCBrZXkgdG8gc3BlY2lmaWMgSVAgYWRkcmVzc2VzXG4gICAqIFdoZW4gc2V0LCBvbmx5IHJlcXVlc3RzIGZyb20gdGhlc2UgSVBzIGNhbiB1c2UgdGhpcyBrZXlcbiAgICovXG4gIGFsbG93ZWRJcHM/OiBzdHJpbmdbXTtcblxuICAvKiogRXhwaXJhdGlvbiBkYXRlIGZvciB0aGUga2V5ICovXG4gIGV4cGlyZXNBdD86IERhdGU7XG59XG5cbi8qKlxuICogQVBJIGtleSBtZXRhZGF0YSAocmV0dXJuZWQgZnJvbSBzZXJ2ZXIpXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXBpS2V5IHtcbiAgLyoqIFVuaXF1ZSBrZXkgSUQgKi9cbiAgaWQ6IHN0cmluZztcbiAgLyoqIERpc3BsYXkgbmFtZSAqL1xuICBuYW1lOiBzdHJpbmc7XG4gIC8qKiBLZXkgcHJlZml4IChmaXJzdCA4IGNoYXJzIGZvciBpZGVudGlmaWNhdGlvbikgKi9cbiAga2V5UHJlZml4OiBzdHJpbmc7XG4gIC8qKiBQZXJtaXNzaW9uIGNvbmZpZ3VyYXRpb24gKi9cbiAgcGVybWlzc2lvbnM6IEFwaUtleVBlcm1pc3Npb25zIHwgc3RyaW5nW107XG4gIC8qKiBTY29wZSB0eXBlICovXG4gIHNjb3BlVHlwZTogU2NvcGVUeXBlO1xuICAvKiogRW52aXJvbm1lbnQgKi9cbiAgZW52aXJvbm1lbnQ6IEVudmlyb25tZW50O1xuICAvKiogQWxsb3dlZCBhZ2VudCBJRHMgKG51bGwgPSBhbGwgYWdlbnRzKSAqL1xuICBhbGxvd2VkQWdlbnRJZHM6IHN0cmluZ1tdIHwgbnVsbDtcbiAgLyoqIEFsbG93ZWQgSVAgYWRkcmVzc2VzIChudWxsID0gYWxsIElQcykgKi9cbiAgYWxsb3dlZElwczogc3RyaW5nW10gfCBudWxsO1xuICAvKiogV2hldGhlciBrZXkgaXMgYWN0aXZlICovXG4gIGlzQWN0aXZlOiBib29sZWFuO1xuICAvKiogTGFzdCB1c2FnZSB0aW1lc3RhbXAgKi9cbiAgbGFzdFVzZWRBdDogc3RyaW5nIHwgbnVsbDtcbiAgLyoqIFRvdGFsIHVzYWdlIGNvdW50ICovXG4gIHVzYWdlQ291bnQ6IG51bWJlcjtcbiAgLyoqIEV4cGlyYXRpb24gZGF0ZSAqL1xuICBleHBpcmVzQXQ6IHN0cmluZyB8IG51bGw7XG4gIC8qKiBDcmVhdGlvbiB0aW1lc3RhbXAgKi9cbiAgY3JlYXRlZEF0OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIGNyZWF0aW5nIGFuIEFQSSBrZXkgKGluY2x1ZGVzIHNlY3JldClcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDcmVhdGVBcGlLZXlSZXN1bHQgZXh0ZW5kcyBBcGlLZXkge1xuICAvKipcbiAgICogVGhlIGZ1bGwgQVBJIGtleSB2YWx1ZVxuICAgKiBJTVBPUlRBTlQ6IFRoaXMgaXMgb25seSByZXR1cm5lZCBvbmNlIGFuZCBjYW5ub3QgYmUgcmV0cmlldmVkIGxhdGVyIVxuICAgKiBTdG9yZSBpdCBzZWN1cmVseS5cbiAgICovXG4gIGtleTogc3RyaW5nO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBBUEkgS2V5IE1hbmFnZW1lbnQgRnVuY3Rpb25zXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogQ3JlYXRlIGEgbmV3IEFQSSBrZXkgd2l0aCBzcGVjaWZpZWQgcGVybWlzc2lvbnMgYW5kIHNjb3BpbmdcbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIEFQSSBrZXkgY29uZmlndXJhdGlvblxuICogQHJldHVybnMgQ3JlYXRlZCBrZXkgd2l0aCBzZWNyZXQgKG9ubHkgcmV0dXJuZWQgb25jZSEpXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIENyZWF0ZSBhIHByb2R1Y3Rpb24gd3JpdGUga2V5XG4gKiBjb25zdCByZXN1bHQgPSBhd2FpdCBhcGlLZXlzLmNyZWF0ZSh7XG4gKiAgIG5hbWU6ICdQcm9kdWN0aW9uIFNESyBLZXknLFxuICogICBwZXJtaXNzaW9uczogeyByZWFkOiB0cnVlLCB3cml0ZTogdHJ1ZSwgZGVsZXRlOiBmYWxzZSB9XG4gKiB9KTtcbiAqXG4gKiAvLyBTYXZlIHRoZSBrZXkgc2VjdXJlbHkgLSBpdCB3b24ndCBiZSBzaG93biBhZ2FpbiFcbiAqIGNvbnNvbGUubG9nKCdTYXZlIHRoaXMga2V5OicsIHJlc3VsdC5rZXkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGUob3B0aW9uczogQ3JlYXRlQXBpS2V5T3B0aW9ucyk6IFByb21pc2U8Q3JlYXRlQXBpS2V5UmVzdWx0PiB7XG4gIGlmICghb3B0aW9ucy5uYW1lIHx8IG9wdGlvbnMubmFtZS50cmltKCkubGVuZ3RoID09PSAwKSB7XG4gICAgdGhyb3cgbmV3IFRoaW5rSGl2ZVZhbGlkYXRpb25FcnJvcignQVBJIGtleSBuYW1lIGlzIHJlcXVpcmVkJywgJ25hbWUnKTtcbiAgfVxuXG4gIC8vIFZhbGlkYXRlIElQIGFkZHJlc3NlcyBpZiBwcm92aWRlZFxuICBpZiAob3B0aW9ucy5hbGxvd2VkSXBzKSB7XG4gICAgLy8gSVB2NCBwYXR0ZXJuXG4gICAgY29uc3QgaXB2NFJlZ2V4ID0gL14oPzooPzoyNVswLTVdfDJbMC00XVswLTldfFswMV0/WzAtOV1bMC05XT8pXFwuKXszfSg/OjI1WzAtNV18MlswLTRdWzAtOV18WzAxXT9bMC05XVswLTldPykkLztcbiAgICAvLyBJUHY2IHBhdHRlcm4gKHN1cHBvcnRzIGZ1bGwgYW5kIGNvbXByZXNzZWQgbm90YXRpb24gbGlrZSA6OjEsIDIwMDE6ZGI4OjoxKVxuICAgIGNvbnN0IGlwdjZSZWdleCA9IC9eKD86KD86WzAtOWEtZkEtRl17MSw0fTopezd9WzAtOWEtZkEtRl17MSw0fXwoPzpbMC05YS1mQS1GXXsxLDR9Oil7MSw3fTp8KD86WzAtOWEtZkEtRl17MSw0fTopezEsNn06WzAtOWEtZkEtRl17MSw0fXwoPzpbMC05YS1mQS1GXXsxLDR9Oil7MSw1fSg/OjpbMC05YS1mQS1GXXsxLDR9KXsxLDJ9fCg/OlswLTlhLWZBLUZdezEsNH06KXsxLDR9KD86OlswLTlhLWZBLUZdezEsNH0pezEsM318KD86WzAtOWEtZkEtRl17MSw0fTopezEsM30oPzo6WzAtOWEtZkEtRl17MSw0fSl7MSw0fXwoPzpbMC05YS1mQS1GXXsxLDR9Oil7MSwyfSg/OjpbMC05YS1mQS1GXXsxLDR9KXsxLDV9fFswLTlhLWZBLUZdezEsNH06KD86OlswLTlhLWZBLUZdezEsNH0pezEsNn18Oig/OjpbMC05YS1mQS1GXXsxLDR9KXsxLDd9fDo6KSQvO1xuICAgIGZvciAoY29uc3QgaXAgb2Ygb3B0aW9ucy5hbGxvd2VkSXBzKSB7XG4gICAgICBpZiAoIWlwdjRSZWdleC50ZXN0KGlwKSAmJiAhaXB2NlJlZ2V4LnRlc3QoaXApICYmIGlwICE9PSAnbG9jYWxob3N0Jykge1xuICAgICAgICB0aHJvdyBuZXcgVGhpbmtIaXZlVmFsaWRhdGlvbkVycm9yKGBJbnZhbGlkIElQIGFkZHJlc3M6ICR7aXB9YCwgJ2FsbG93ZWRJcHMnKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zdCBib2R5OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHtcbiAgICBuYW1lOiBvcHRpb25zLm5hbWUudHJpbSgpLFxuICB9O1xuXG4gIGlmIChvcHRpb25zLnBlcm1pc3Npb25zKSB7XG4gICAgYm9keS5wZXJtaXNzaW9ucyA9IHtcbiAgICAgIHJlYWQ6IG9wdGlvbnMucGVybWlzc2lvbnMucmVhZCAhPT0gZmFsc2UsXG4gICAgICB3cml0ZTogb3B0aW9ucy5wZXJtaXNzaW9ucy53cml0ZSA9PT0gdHJ1ZSxcbiAgICAgIGRlbGV0ZTogb3B0aW9ucy5wZXJtaXNzaW9ucy5kZWxldGUgPT09IHRydWUsXG4gICAgfTtcbiAgfVxuXG4gIGlmIChvcHRpb25zLnNjb3BlVHlwZSkge1xuICAgIGJvZHkuc2NvcGVUeXBlID0gb3B0aW9ucy5zY29wZVR5cGU7XG4gIH1cblxuICBpZiAob3B0aW9ucy5lbnZpcm9ubWVudCkge1xuICAgIGJvZHkuZW52aXJvbm1lbnQgPSBvcHRpb25zLmVudmlyb25tZW50O1xuICB9XG5cbiAgaWYgKG9wdGlvbnMuYWxsb3dlZEFnZW50SWRzICYmIG9wdGlvbnMuYWxsb3dlZEFnZW50SWRzLmxlbmd0aCA+IDApIHtcbiAgICBib2R5LmFsbG93ZWRBZ2VudElkcyA9IG9wdGlvbnMuYWxsb3dlZEFnZW50SWRzO1xuICB9XG5cbiAgaWYgKG9wdGlvbnMuYWxsb3dlZElwcyAmJiBvcHRpb25zLmFsbG93ZWRJcHMubGVuZ3RoID4gMCkge1xuICAgIGJvZHkuYWxsb3dlZElwcyA9IG9wdGlvbnMuYWxsb3dlZElwcztcbiAgfVxuXG4gIGlmIChvcHRpb25zLmV4cGlyZXNBdCkge1xuICAgIGJvZHkuZXhwaXJlc0F0ID0gb3B0aW9ucy5leHBpcmVzQXQudG9JU09TdHJpbmcoKTtcbiAgfVxuXG4gIHJldHVybiBhcGlSZXF1ZXN0PENyZWF0ZUFwaUtleVJlc3VsdD4oJy9hcGkta2V5cycsIHtcbiAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICBib2R5LFxuICAgIGFwaVZlcnNpb246ICd2MicsXG4gIH0pO1xufVxuXG4vKipcbiAqIExpc3QgYWxsIEFQSSBrZXlzIGZvciB0aGUgYXV0aGVudGljYXRlZCBjb21wYW55XG4gKlxuICogQHJldHVybnMgQXJyYXkgb2YgQVBJIGtleXMgKHdpdGhvdXQgc2VjcmV0cylcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3Qga2V5cyA9IGF3YWl0IGFwaUtleXMubGlzdCgpO1xuICogY29uc29sZS5sb2coYEZvdW5kICR7a2V5cy5sZW5ndGh9IEFQSSBrZXlzYCk7XG4gKlxuICogLy8gRmlsdGVyIGJ5IGVudmlyb25tZW50XG4gKiBjb25zdCBwcm9kS2V5cyA9IGtleXMuZmlsdGVyKGsgPT4gay5lbnZpcm9ubWVudCA9PT0gJ3Byb2R1Y3Rpb24nKTtcbiAqIGBgYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbGlzdCgpOiBQcm9taXNlPEFwaUtleVtdPiB7XG4gIHJldHVybiBhcGlSZXF1ZXN0PEFwaUtleVtdPignL2FwaS1rZXlzJywge1xuICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgYXBpVmVyc2lvbjogJ3YyJyxcbiAgfSk7XG59XG5cbi8qKlxuICogUmV2b2tlIChkZWFjdGl2YXRlKSBhbiBBUEkga2V5XG4gKlxuICogQHBhcmFtIGtleUlkIC0gSUQgb2YgdGhlIGtleSB0byByZXZva2VcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gUmV2b2tlIGEgY29tcHJvbWlzZWQga2V5XG4gKiBhd2FpdCBhcGlLZXlzLnJldm9rZSgna2V5LWlkLXRvLXJldm9rZScpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXZva2Uoa2V5SWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoIWtleUlkKSB7XG4gICAgdGhyb3cgbmV3IFRoaW5rSGl2ZVZhbGlkYXRpb25FcnJvcignS2V5IElEIGlzIHJlcXVpcmVkJywgJ2tleUlkJyk7XG4gIH1cblxuICBhd2FpdCBhcGlSZXF1ZXN0KGAvYXBpLWtleXMvJHtrZXlJZH1gLCB7XG4gICAgbWV0aG9kOiAnREVMRVRFJyxcbiAgICBhcGlWZXJzaW9uOiAndjInLFxuICB9KTtcbn1cblxuLyoqXG4gKiBSb3RhdGUgYW4gQVBJIGtleSAocmV2b2tlIG9sZCwgY3JlYXRlIG5ldyB3aXRoIHNhbWUgY29uZmlnKVxuICpcbiAqIEBwYXJhbSBrZXlJZCAtIElEIG9mIHRoZSBrZXkgdG8gcm90YXRlXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIG92ZXJyaWRlcyBmb3IgdGhlIG5ldyBrZXlcbiAqIEByZXR1cm5zIE5ldyBrZXkgd2l0aCBzZWNyZXRcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gUm90YXRlIGEga2V5IHBlcmlvZGljYWxseVxuICogY29uc3QgZXhpc3RpbmdLZXlzID0gYXdhaXQgYXBpS2V5cy5saXN0KCk7XG4gKiBjb25zdCBvbGRLZXkgPSBleGlzdGluZ0tleXMuZmluZChrID0+IGsubmFtZSA9PT0gJ1Byb2R1Y3Rpb24gS2V5Jyk7XG4gKlxuICogaWYgKG9sZEtleSkge1xuICogICBjb25zdCBuZXdLZXkgPSBhd2FpdCBhcGlLZXlzLnJvdGF0ZShvbGRLZXkuaWQpO1xuICogICAvLyBVcGRhdGUgeW91ciBzeXN0ZW1zIHdpdGggbmV3S2V5LmtleVxuICogICBjb25zb2xlLmxvZygnTmV3IGtleTonLCBuZXdLZXkua2V5KTtcbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcm90YXRlKFxuICBrZXlJZDogc3RyaW5nLFxuICBvcHRpb25zPzogUGFydGlhbDxDcmVhdGVBcGlLZXlPcHRpb25zPlxuKTogUHJvbWlzZTxDcmVhdGVBcGlLZXlSZXN1bHQ+IHtcbiAgLy8gR2V0IGV4aXN0aW5nIGtleSBtZXRhZGF0YVxuICBjb25zdCBrZXlzID0gYXdhaXQgbGlzdCgpO1xuICBjb25zdCBleGlzdGluZ0tleSA9IGtleXMuZmluZChrID0+IGsuaWQgPT09IGtleUlkKTtcblxuICBpZiAoIWV4aXN0aW5nS2V5KSB7XG4gICAgdGhyb3cgbmV3IFRoaW5rSGl2ZVZhbGlkYXRpb25FcnJvcignQVBJIGtleSBub3QgZm91bmQnLCAna2V5SWQnKTtcbiAgfVxuXG4gIC8vIENyZWF0ZSBuZXcga2V5IHdpdGggc2FtZSAob3Igb3ZlcnJpZGRlbikgY29uZmlnXG4gIGNvbnN0IG5ld0tleU9wdGlvbnM6IENyZWF0ZUFwaUtleU9wdGlvbnMgPSB7XG4gICAgbmFtZTogb3B0aW9ucz8ubmFtZSB8fCBleGlzdGluZ0tleS5uYW1lLFxuICAgIHNjb3BlVHlwZTogb3B0aW9ucz8uc2NvcGVUeXBlIHx8IGV4aXN0aW5nS2V5LnNjb3BlVHlwZSxcbiAgICBlbnZpcm9ubWVudDogb3B0aW9ucz8uZW52aXJvbm1lbnQgfHwgZXhpc3RpbmdLZXkuZW52aXJvbm1lbnQsXG4gICAgYWxsb3dlZEFnZW50SWRzOiBvcHRpb25zPy5hbGxvd2VkQWdlbnRJZHMgfHwgZXhpc3RpbmdLZXkuYWxsb3dlZEFnZW50SWRzIHx8IHVuZGVmaW5lZCxcbiAgICBhbGxvd2VkSXBzOiBvcHRpb25zPy5hbGxvd2VkSXBzIHx8IGV4aXN0aW5nS2V5LmFsbG93ZWRJcHMgfHwgdW5kZWZpbmVkLFxuICB9O1xuXG4gIC8vIEhhbmRsZSBwZXJtaXNzaW9ucyBjb252ZXJzaW9uXG4gIGlmIChvcHRpb25zPy5wZXJtaXNzaW9ucykge1xuICAgIG5ld0tleU9wdGlvbnMucGVybWlzc2lvbnMgPSBvcHRpb25zLnBlcm1pc3Npb25zO1xuICB9IGVsc2UgaWYgKGV4aXN0aW5nS2V5LnBlcm1pc3Npb25zICYmIHR5cGVvZiBleGlzdGluZ0tleS5wZXJtaXNzaW9ucyA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoZXhpc3RpbmdLZXkucGVybWlzc2lvbnMpKSB7XG4gICAgbmV3S2V5T3B0aW9ucy5wZXJtaXNzaW9ucyA9IGV4aXN0aW5nS2V5LnBlcm1pc3Npb25zIGFzIEFwaUtleVBlcm1pc3Npb25zO1xuICB9XG5cbiAgLy8gQ3JlYXRlIG5ldyBrZXkgZmlyc3QgKHNvIHdlIGRvbid0IGxvc2UgYWNjZXNzIGlmIGNyZWF0aW9uIGZhaWxzKVxuICBjb25zdCBuZXdLZXkgPSBhd2FpdCBjcmVhdGUobmV3S2V5T3B0aW9ucyk7XG5cbiAgLy8gUmV2b2tlIG9sZCBrZXlcbiAgYXdhaXQgcmV2b2tlKGtleUlkKTtcblxuICByZXR1cm4gbmV3S2V5O1xufVxuXG4vKipcbiAqIFRlc3QgYW4gQVBJIGtleSBjb25uZWN0aW9uXG4gKlxuICogQHBhcmFtIGFwaUtleSAtIFRoZSBmdWxsIEFQSSBrZXkgdmFsdWUgdG8gdGVzdFxuICogQHBhcmFtIGFnZW50SWQgLSBPcHRpb25hbCBhZ2VudCBJRCB0byB0ZXN0IHdpdGhcbiAqIEByZXR1cm5zIFRlc3QgcmVzdWx0XG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGFwaUtleXMudGVzdCgndGhrXy4uLicsICdteS1hZ2VudC1pZCcpO1xuICogaWYgKHJlc3VsdC5zdWNjZXNzKSB7XG4gKiAgIGNvbnNvbGUubG9nKCdLZXkgaXMgdmFsaWQhJyk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRlc3QoXG4gIGFwaUtleTogc3RyaW5nLFxuICBhZ2VudElkPzogc3RyaW5nXG4pOiBQcm9taXNlPHsgc3VjY2VzczogYm9vbGVhbjsgZXJyb3I/OiBzdHJpbmc7IHRlc3RUcmFjZUlkPzogc3RyaW5nIH0+IHtcbiAgaWYgKCFhcGlLZXkpIHtcbiAgICB0aHJvdyBuZXcgVGhpbmtIaXZlVmFsaWRhdGlvbkVycm9yKCdBUEkga2V5IGlzIHJlcXVpcmVkJywgJ2FwaUtleScpO1xuICB9XG5cbiAgcmV0dXJuIGFwaVJlcXVlc3Q8eyBzdWNjZXNzOiBib29sZWFuOyBlcnJvcj86IHN0cmluZzsgdGVzdFRyYWNlSWQ/OiBzdHJpbmcgfT4oJy9hcGkta2V5cy90ZXN0Jywge1xuICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgIGJvZHk6IHsgYXBpS2V5LCBhZ2VudElkLCBjcmVhdGVUZXN0VHJhY2U6ICEhYWdlbnRJZCB9LFxuICAgIGFwaVZlcnNpb246ICd2MicsXG4gIH0pO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBVdGlsaXR5IEZ1bmN0aW9uc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIENoZWNrIGlmIGFuIEFQSSBrZXkgaGFzIGEgc3BlY2lmaWMgcGVybWlzc2lvblxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzUGVybWlzc2lvbihcbiAga2V5OiBBcGlLZXksXG4gIHBlcm1pc3Npb246ICdyZWFkJyB8ICd3cml0ZScgfCAnZGVsZXRlJ1xuKTogYm9vbGVhbiB7XG4gIC8vIEhhbmRsZSBvYmplY3QgZm9ybWF0XG4gIGlmICh0eXBlb2Yga2V5LnBlcm1pc3Npb25zID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShrZXkucGVybWlzc2lvbnMpKSB7XG4gICAgcmV0dXJuIGtleS5wZXJtaXNzaW9uc1twZXJtaXNzaW9uXSA9PT0gdHJ1ZTtcbiAgfVxuXG4gIC8vIEhhbmRsZSBsZWdhY3kgYXJyYXkgZm9ybWF0XG4gIGlmIChBcnJheS5pc0FycmF5KGtleS5wZXJtaXNzaW9ucykpIHtcbiAgICByZXR1cm4ga2V5LnBlcm1pc3Npb25zLnNvbWUocCA9PiBwLmVuZHNXaXRoKGA6JHtwZXJtaXNzaW9ufWApKTtcbiAgfVxuXG4gIC8vIERlZmF1bHQ6IHJlYWQgYWxsb3dlZCwgd3JpdGUvZGVsZXRlIGRlbmllZFxuICByZXR1cm4gcGVybWlzc2lvbiA9PT0gJ3JlYWQnO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIGFuIEFQSSBrZXkgaXMgZXhwaXJlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNFeHBpcmVkKGtleTogQXBpS2V5KTogYm9vbGVhbiB7XG4gIGlmICgha2V5LmV4cGlyZXNBdCkgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gbmV3IERhdGUoa2V5LmV4cGlyZXNBdCkgPCBuZXcgRGF0ZSgpO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIGFuIEFQSSBrZXkgaXMgdmFsaWQgKGFjdGl2ZSBhbmQgbm90IGV4cGlyZWQpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1ZhbGlkKGtleTogQXBpS2V5KTogYm9vbGVhbiB7XG4gIHJldHVybiBrZXkuaXNBY3RpdmUgJiYgIWlzRXhwaXJlZChrZXkpO1xufVxuXG4vKipcbiAqIEdldCB0aW1lIHVudGlsIGtleSBleHBpcmVzIChpbiBtaWxsaXNlY29uZHMpXG4gKiBSZXR1cm5zIG51bGwgaWYga2V5IGRvZXNuJ3QgZXhwaXJlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRUaW1lVW50aWxFeHBpcnkoa2V5OiBBcGlLZXkpOiBudW1iZXIgfCBudWxsIHtcbiAgaWYgKCFrZXkuZXhwaXJlc0F0KSByZXR1cm4gbnVsbDtcbiAgY29uc3QgZXhwaXJ5ID0gbmV3IERhdGUoa2V5LmV4cGlyZXNBdCkuZ2V0VGltZSgpO1xuICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICByZXR1cm4gTWF0aC5tYXgoMCwgZXhwaXJ5IC0gbm93KTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBhIGtleSBjYW4gYWNjZXNzIGEgc3BlY2lmaWMgYWdlbnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhbkFjY2Vzc0FnZW50KGtleTogQXBpS2V5LCBhZ2VudElkOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgLy8gSWYgbm8gYWdlbnQgcmVzdHJpY3Rpb25zLCBhbGxvdyBhbGxcbiAgaWYgKCFrZXkuYWxsb3dlZEFnZW50SWRzIHx8IGtleS5hbGxvd2VkQWdlbnRJZHMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgcmV0dXJuIGtleS5hbGxvd2VkQWdlbnRJZHMuaW5jbHVkZXMoYWdlbnRJZCk7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEV4cG9ydCBuYW1lc3BhY2Vcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGNvbnN0IGFwaUtleXMgPSB7XG4gIGNyZWF0ZSxcbiAgbGlzdCxcbiAgcmV2b2tlLFxuICByb3RhdGUsXG4gIHRlc3QsXG4gIGhhc1Blcm1pc3Npb24sXG4gIGlzRXhwaXJlZCxcbiAgaXNWYWxpZCxcbiAgZ2V0VGltZVVudGlsRXhwaXJ5LFxuICBjYW5BY2Nlc3NBZ2VudCxcbn07XG4iXX0=
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ThinkHive SDK v3.2 - Business Metrics API
|
|
3
|
+
*
|
|
4
|
+
* Industry-driven business metrics with historical tracking and external data support
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Metric trend information
|
|
8
|
+
*/
|
|
9
|
+
export interface MetricTrend {
|
|
10
|
+
direction: 'up' | 'down' | 'stable';
|
|
11
|
+
value: number;
|
|
12
|
+
isPositive: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Current metric status
|
|
16
|
+
*/
|
|
17
|
+
export type MetricStatus = 'ready' | 'insufficient_data' | 'awaiting_external' | 'stale';
|
|
18
|
+
/**
|
|
19
|
+
* Current metric response from the API
|
|
20
|
+
*/
|
|
21
|
+
export interface CurrentMetricResponse {
|
|
22
|
+
metricName: string;
|
|
23
|
+
metricType: 'trace_calculated' | 'external';
|
|
24
|
+
value: number | null;
|
|
25
|
+
valueFormatted: string;
|
|
26
|
+
unit?: string;
|
|
27
|
+
status: MetricStatus;
|
|
28
|
+
statusMessage?: string;
|
|
29
|
+
trend?: MetricTrend;
|
|
30
|
+
traceCount?: number;
|
|
31
|
+
minTraceThreshold?: number;
|
|
32
|
+
progressPercent?: number;
|
|
33
|
+
lastExternalUpdate?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Historical data point
|
|
37
|
+
*/
|
|
38
|
+
export interface MetricHistoryPoint {
|
|
39
|
+
periodStart: string;
|
|
40
|
+
periodEnd: string;
|
|
41
|
+
value: number;
|
|
42
|
+
valueFormatted?: string;
|
|
43
|
+
source: string;
|
|
44
|
+
traceCount?: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Historical summary statistics
|
|
48
|
+
*/
|
|
49
|
+
export interface MetricHistorySummary {
|
|
50
|
+
current: number | null;
|
|
51
|
+
previous: number | null;
|
|
52
|
+
changePercent: number | null;
|
|
53
|
+
isPositive: boolean;
|
|
54
|
+
dataPointCount: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Full history response
|
|
58
|
+
*/
|
|
59
|
+
export interface MetricHistoryResponse {
|
|
60
|
+
metricName: string;
|
|
61
|
+
unit: string;
|
|
62
|
+
higherIsBetter: boolean;
|
|
63
|
+
dataPoints: MetricHistoryPoint[];
|
|
64
|
+
summary: MetricHistorySummary;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Options for recording external metric values
|
|
68
|
+
*/
|
|
69
|
+
export interface RecordMetricOptions {
|
|
70
|
+
metricName: string;
|
|
71
|
+
value: number;
|
|
72
|
+
unit?: string;
|
|
73
|
+
periodStart: string | Date;
|
|
74
|
+
periodEnd: string | Date;
|
|
75
|
+
source?: string;
|
|
76
|
+
sourceDetails?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Response from recording a metric value
|
|
80
|
+
*/
|
|
81
|
+
export interface RecordMetricResponse {
|
|
82
|
+
success: boolean;
|
|
83
|
+
id: string;
|
|
84
|
+
recordedAt: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Business Metrics API client for industry-driven metrics with historical tracking
|
|
88
|
+
*/
|
|
89
|
+
export declare const businessMetrics: {
|
|
90
|
+
/**
|
|
91
|
+
* Get current metric value with status information
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const metric = await businessMetrics.current('agent_123', 'Deflection Rate');
|
|
96
|
+
* console.log(`${metric.metricName}: ${metric.valueFormatted}`);
|
|
97
|
+
*
|
|
98
|
+
* if (metric.status === 'insufficient_data') {
|
|
99
|
+
* console.log(`Need ${metric.minTraceThreshold - metric.traceCount} more traces`);
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
current(agentId: string, metricName?: string): Promise<CurrentMetricResponse>;
|
|
104
|
+
/**
|
|
105
|
+
* Get historical metric data for graphing
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const history = await businessMetrics.history('agent_123', 'Deflection Rate', {
|
|
110
|
+
* startDate: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
|
|
111
|
+
* endDate: new Date(),
|
|
112
|
+
* granularity: 'daily',
|
|
113
|
+
* });
|
|
114
|
+
*
|
|
115
|
+
* console.log(`${history.dataPoints.length} data points`);
|
|
116
|
+
* console.log(`Change: ${history.summary.changePercent}%`);
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
history(agentId: string, metricName: string, options?: {
|
|
120
|
+
startDate?: string | Date;
|
|
121
|
+
endDate?: string | Date;
|
|
122
|
+
granularity?: "hourly" | "daily" | "weekly" | "monthly";
|
|
123
|
+
}): Promise<MetricHistoryResponse>;
|
|
124
|
+
/**
|
|
125
|
+
* Record an external metric value
|
|
126
|
+
*
|
|
127
|
+
* Use this to ingest metrics from external data sources (CRM, surveys, billing, etc.)
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* // Record CSAT score from survey system
|
|
132
|
+
* await businessMetrics.record('agent_123', {
|
|
133
|
+
* metricName: 'CSAT/NPS',
|
|
134
|
+
* value: 4.5,
|
|
135
|
+
* unit: 'score',
|
|
136
|
+
* periodStart: '2024-01-01T00:00:00Z',
|
|
137
|
+
* periodEnd: '2024-01-07T23:59:59Z',
|
|
138
|
+
* source: 'survey_system',
|
|
139
|
+
* sourceDetails: { surveyId: 'survey_456', responseCount: 150 },
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
record(agentId: string, options: RecordMetricOptions): Promise<RecordMetricResponse>;
|
|
144
|
+
/**
|
|
145
|
+
* Batch record multiple external metric values
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* await businessMetrics.recordBatch('agent_123', [
|
|
150
|
+
* { metricName: 'CSAT/NPS', value: 4.5, ... },
|
|
151
|
+
* { metricName: 'Hours Saved', value: 120, ... },
|
|
152
|
+
* ]);
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
recordBatch(agentId: string, metrics: RecordMetricOptions[]): Promise<RecordMetricResponse[]>;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Check if a metric is ready to display
|
|
159
|
+
*/
|
|
160
|
+
export declare function isMetricReady(metric: CurrentMetricResponse): boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Check if a metric needs more trace data
|
|
163
|
+
*/
|
|
164
|
+
export declare function needsMoreTraces(metric: CurrentMetricResponse): boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Check if a metric is waiting for external data
|
|
167
|
+
*/
|
|
168
|
+
export declare function awaitingExternalData(metric: CurrentMetricResponse): boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Check if metric data is stale
|
|
171
|
+
*/
|
|
172
|
+
export declare function isMetricStale(metric: CurrentMetricResponse): boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Get human-readable status message
|
|
175
|
+
*/
|
|
176
|
+
export declare function getStatusMessage(metric: CurrentMetricResponse): string;
|
|
177
|
+
/**
|
|
178
|
+
* Calculate progress toward minimum trace threshold
|
|
179
|
+
*/
|
|
180
|
+
export declare function getTraceProgress(metric: CurrentMetricResponse): number;
|
|
181
|
+
/**
|
|
182
|
+
* Format metric value for display based on unit
|
|
183
|
+
*/
|
|
184
|
+
export declare function formatMetricValue(value: number, unit: string): string;
|
|
185
|
+
/**
|
|
186
|
+
* Get trend direction as emoji
|
|
187
|
+
*/
|
|
188
|
+
export declare function getTrendEmoji(trend: MetricTrend): string;
|