@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.
@@ -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;