@zincapp/znvault-cli 2.1.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.
Files changed (122) hide show
  1. package/README.md +310 -0
  2. package/dist/commands/agent.d.ts +3 -0
  3. package/dist/commands/agent.d.ts.map +1 -0
  4. package/dist/commands/agent.js +660 -0
  5. package/dist/commands/agent.js.map +1 -0
  6. package/dist/commands/apikey.d.ts +3 -0
  7. package/dist/commands/apikey.d.ts.map +1 -0
  8. package/dist/commands/apikey.js +767 -0
  9. package/dist/commands/apikey.js.map +1 -0
  10. package/dist/commands/audit.d.ts +3 -0
  11. package/dist/commands/audit.d.ts.map +1 -0
  12. package/dist/commands/audit.js +147 -0
  13. package/dist/commands/audit.js.map +1 -0
  14. package/dist/commands/auth.d.ts +3 -0
  15. package/dist/commands/auth.d.ts.map +1 -0
  16. package/dist/commands/auth.js +426 -0
  17. package/dist/commands/auth.js.map +1 -0
  18. package/dist/commands/cert.d.ts +3 -0
  19. package/dist/commands/cert.d.ts.map +1 -0
  20. package/dist/commands/cert.js +398 -0
  21. package/dist/commands/cert.js.map +1 -0
  22. package/dist/commands/cluster.d.ts +3 -0
  23. package/dist/commands/cluster.d.ts.map +1 -0
  24. package/dist/commands/cluster.js +228 -0
  25. package/dist/commands/cluster.js.map +1 -0
  26. package/dist/commands/emergency.d.ts +3 -0
  27. package/dist/commands/emergency.d.ts.map +1 -0
  28. package/dist/commands/emergency.js +223 -0
  29. package/dist/commands/emergency.js.map +1 -0
  30. package/dist/commands/health.d.ts +3 -0
  31. package/dist/commands/health.d.ts.map +1 -0
  32. package/dist/commands/health.js +188 -0
  33. package/dist/commands/health.js.map +1 -0
  34. package/dist/commands/lockdown.d.ts +3 -0
  35. package/dist/commands/lockdown.d.ts.map +1 -0
  36. package/dist/commands/lockdown.js +232 -0
  37. package/dist/commands/lockdown.js.map +1 -0
  38. package/dist/commands/permissions.d.ts +3 -0
  39. package/dist/commands/permissions.d.ts.map +1 -0
  40. package/dist/commands/permissions.js +168 -0
  41. package/dist/commands/permissions.js.map +1 -0
  42. package/dist/commands/policy.d.ts +3 -0
  43. package/dist/commands/policy.d.ts.map +1 -0
  44. package/dist/commands/policy.js +660 -0
  45. package/dist/commands/policy.js.map +1 -0
  46. package/dist/commands/superadmin.d.ts +3 -0
  47. package/dist/commands/superadmin.d.ts.map +1 -0
  48. package/dist/commands/superadmin.js +203 -0
  49. package/dist/commands/superadmin.js.map +1 -0
  50. package/dist/commands/tenant.d.ts +3 -0
  51. package/dist/commands/tenant.d.ts.map +1 -0
  52. package/dist/commands/tenant.js +277 -0
  53. package/dist/commands/tenant.js.map +1 -0
  54. package/dist/commands/update.d.ts +9 -0
  55. package/dist/commands/update.d.ts.map +1 -0
  56. package/dist/commands/update.js +359 -0
  57. package/dist/commands/update.js.map +1 -0
  58. package/dist/commands/user.d.ts +3 -0
  59. package/dist/commands/user.d.ts.map +1 -0
  60. package/dist/commands/user.js +363 -0
  61. package/dist/commands/user.js.map +1 -0
  62. package/dist/index.d.ts +3 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +82 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/lib/client.d.ts +246 -0
  67. package/dist/lib/client.d.ts.map +1 -0
  68. package/dist/lib/client.js +734 -0
  69. package/dist/lib/client.js.map +1 -0
  70. package/dist/lib/config.d.ts +130 -0
  71. package/dist/lib/config.d.ts.map +1 -0
  72. package/dist/lib/config.js +342 -0
  73. package/dist/lib/config.js.map +1 -0
  74. package/dist/lib/db.d.ts +111 -0
  75. package/dist/lib/db.d.ts.map +1 -0
  76. package/dist/lib/db.js +698 -0
  77. package/dist/lib/db.js.map +1 -0
  78. package/dist/lib/local.d.ts +41 -0
  79. package/dist/lib/local.d.ts.map +1 -0
  80. package/dist/lib/local.js +236 -0
  81. package/dist/lib/local.js.map +1 -0
  82. package/dist/lib/mode.d.ts +210 -0
  83. package/dist/lib/mode.d.ts.map +1 -0
  84. package/dist/lib/mode.js +389 -0
  85. package/dist/lib/mode.js.map +1 -0
  86. package/dist/lib/output.d.ts +61 -0
  87. package/dist/lib/output.d.ts.map +1 -0
  88. package/dist/lib/output.js +190 -0
  89. package/dist/lib/output.js.map +1 -0
  90. package/dist/lib/prompts.d.ts +32 -0
  91. package/dist/lib/prompts.d.ts.map +1 -0
  92. package/dist/lib/prompts.js +96 -0
  93. package/dist/lib/prompts.js.map +1 -0
  94. package/dist/services/auto-update-daemon.d.ts +48 -0
  95. package/dist/services/auto-update-daemon.d.ts.map +1 -0
  96. package/dist/services/auto-update-daemon.js +296 -0
  97. package/dist/services/auto-update-daemon.js.map +1 -0
  98. package/dist/services/signature-verifier.d.ts +38 -0
  99. package/dist/services/signature-verifier.d.ts.map +1 -0
  100. package/dist/services/signature-verifier.js +209 -0
  101. package/dist/services/signature-verifier.js.map +1 -0
  102. package/dist/services/update-checker.d.ts +39 -0
  103. package/dist/services/update-checker.d.ts.map +1 -0
  104. package/dist/services/update-checker.js +198 -0
  105. package/dist/services/update-checker.js.map +1 -0
  106. package/dist/services/update-installer.d.ts +54 -0
  107. package/dist/services/update-installer.d.ts.map +1 -0
  108. package/dist/services/update-installer.js +360 -0
  109. package/dist/services/update-installer.js.map +1 -0
  110. package/dist/types/index.d.ts +411 -0
  111. package/dist/types/index.d.ts.map +1 -0
  112. package/dist/types/index.js +2 -0
  113. package/dist/types/index.js.map +1 -0
  114. package/dist/types/update.d.ts +137 -0
  115. package/dist/types/update.d.ts.map +1 -0
  116. package/dist/types/update.js +27 -0
  117. package/dist/types/update.js.map +1 -0
  118. package/dist/utils/platform.d.ts +35 -0
  119. package/dist/utils/platform.d.ts.map +1 -0
  120. package/dist/utils/platform.js +115 -0
  121. package/dist/utils/platform.js.map +1 -0
  122. package/package.json +59 -0
@@ -0,0 +1,734 @@
1
+ import https from 'node:https';
2
+ import http from 'node:http';
3
+ import { getConfig, getCredentials, getApiKey, hasApiKey, storeCredentials, isTokenExpired, getEnvCredentials, hasEnvCredentials, } from './config.js';
4
+ class VaultClient {
5
+ baseUrl;
6
+ insecure;
7
+ timeout;
8
+ constructor() {
9
+ const config = getConfig();
10
+ this.baseUrl = config.url;
11
+ this.insecure = config.insecure;
12
+ this.timeout = config.timeout;
13
+ }
14
+ /**
15
+ * Update client configuration
16
+ */
17
+ configure(url, insecure) {
18
+ if (url)
19
+ this.baseUrl = url;
20
+ if (insecure !== undefined)
21
+ this.insecure = insecure;
22
+ }
23
+ /**
24
+ * Make an HTTP request
25
+ */
26
+ async request(options) {
27
+ const url = new URL(this.baseUrl);
28
+ url.pathname = options.path;
29
+ if (options.query) {
30
+ for (const [key, value] of Object.entries(options.query)) {
31
+ if (value !== undefined) {
32
+ url.searchParams.set(key, String(value));
33
+ }
34
+ }
35
+ }
36
+ const headers = {
37
+ 'Content-Type': 'application/json',
38
+ 'Accept': 'application/json',
39
+ };
40
+ // Add authentication
41
+ if (!options.skipAuth) {
42
+ if (hasApiKey()) {
43
+ headers['X-API-Key'] = getApiKey();
44
+ }
45
+ else {
46
+ const credentials = getCredentials();
47
+ if (credentials) {
48
+ // Check if token is expired and try to refresh
49
+ if (isTokenExpired() && credentials.refreshToken) {
50
+ await this.refreshToken();
51
+ }
52
+ const updatedCredentials = getCredentials();
53
+ if (updatedCredentials) {
54
+ headers['Authorization'] = `Bearer ${updatedCredentials.accessToken}`;
55
+ }
56
+ }
57
+ else if (hasEnvCredentials()) {
58
+ // Auto-login with env credentials
59
+ const envCreds = getEnvCredentials();
60
+ await this.login(envCreds.username, envCreds.password);
61
+ const newCredentials = getCredentials();
62
+ if (newCredentials) {
63
+ headers['Authorization'] = `Bearer ${newCredentials.accessToken}`;
64
+ }
65
+ }
66
+ }
67
+ }
68
+ const requestOptions = {
69
+ hostname: url.hostname,
70
+ port: url.port || (url.protocol === 'https:' ? 443 : 80),
71
+ path: url.pathname + url.search,
72
+ method: options.method,
73
+ headers,
74
+ timeout: this.timeout,
75
+ rejectUnauthorized: !this.insecure,
76
+ };
77
+ return new Promise((resolve, reject) => {
78
+ const protocol = url.protocol === 'https:' ? https : http;
79
+ const req = protocol.request(requestOptions, (res) => {
80
+ let data = '';
81
+ res.on('data', (chunk) => (data += chunk));
82
+ res.on('end', () => {
83
+ try {
84
+ const parsed = data ? JSON.parse(data) : {};
85
+ if (res.statusCode && res.statusCode >= 400) {
86
+ const error = parsed;
87
+ reject(new Error(error.message || `Request failed with status ${res.statusCode}`));
88
+ }
89
+ else {
90
+ resolve(parsed);
91
+ }
92
+ }
93
+ catch {
94
+ if (res.statusCode && res.statusCode >= 400) {
95
+ reject(new Error(`Request failed with status ${res.statusCode}`));
96
+ }
97
+ else {
98
+ resolve(data);
99
+ }
100
+ }
101
+ });
102
+ });
103
+ req.on('error', reject);
104
+ req.on('timeout', () => {
105
+ req.destroy();
106
+ reject(new Error('Request timeout'));
107
+ });
108
+ if (options.body) {
109
+ req.write(JSON.stringify(options.body));
110
+ }
111
+ req.end();
112
+ });
113
+ }
114
+ // ============ Authentication ============
115
+ async login(username, password, totp) {
116
+ const response = await this.request({
117
+ method: 'POST',
118
+ path: '/auth/login',
119
+ body: { username, password, totp },
120
+ skipAuth: true,
121
+ });
122
+ // Store credentials
123
+ storeCredentials({
124
+ accessToken: response.accessToken,
125
+ refreshToken: response.refreshToken,
126
+ expiresAt: Date.now() + response.expiresIn * 1000,
127
+ userId: response.user.id,
128
+ username: response.user.username,
129
+ role: response.user.role,
130
+ tenantId: response.user.tenantId,
131
+ });
132
+ return response;
133
+ }
134
+ async refreshToken() {
135
+ const credentials = getCredentials();
136
+ if (!credentials?.refreshToken) {
137
+ throw new Error('No refresh token available');
138
+ }
139
+ const response = await this.request({
140
+ method: 'POST',
141
+ path: '/auth/refresh',
142
+ body: { refreshToken: credentials.refreshToken },
143
+ skipAuth: true,
144
+ });
145
+ storeCredentials({
146
+ ...credentials,
147
+ accessToken: response.accessToken,
148
+ refreshToken: response.refreshToken,
149
+ expiresAt: Date.now() + response.expiresIn * 1000,
150
+ });
151
+ }
152
+ // ============ Health ============
153
+ async health() {
154
+ return this.request({
155
+ method: 'GET',
156
+ path: '/v1/health',
157
+ skipAuth: true,
158
+ });
159
+ }
160
+ async leaderHealth() {
161
+ return this.request({
162
+ method: 'GET',
163
+ path: '/v1/health/leader',
164
+ skipAuth: true,
165
+ });
166
+ }
167
+ // ============ Cluster ============
168
+ async clusterStatus() {
169
+ return this.request({
170
+ method: 'GET',
171
+ path: '/v1/admin/cluster',
172
+ });
173
+ }
174
+ async clusterTakeover() {
175
+ return this.request({
176
+ method: 'POST',
177
+ path: '/v1/admin/cluster/takeover',
178
+ });
179
+ }
180
+ async clusterPromote(nodeId) {
181
+ return this.request({
182
+ method: 'POST',
183
+ path: `/v1/admin/cluster/nodes/${nodeId}/promote`,
184
+ });
185
+ }
186
+ async clusterRelease() {
187
+ return this.request({
188
+ method: 'POST',
189
+ path: '/v1/admin/cluster/release',
190
+ });
191
+ }
192
+ async clusterMaintenance(enable) {
193
+ return this.request({
194
+ method: 'POST',
195
+ path: '/v1/admin/cluster/maintenance',
196
+ body: { enable },
197
+ });
198
+ }
199
+ // ============ Tenants ============
200
+ async listTenants(options) {
201
+ const response = await this.request({
202
+ method: 'GET',
203
+ path: '/v1/tenants',
204
+ query: {
205
+ status: options?.status,
206
+ withUsage: options?.withUsage,
207
+ pageSize: 1000,
208
+ },
209
+ });
210
+ return response.items;
211
+ }
212
+ async createTenant(data) {
213
+ return this.request({
214
+ method: 'POST',
215
+ path: '/v1/tenants',
216
+ body: data,
217
+ });
218
+ }
219
+ async getTenant(id, withUsage) {
220
+ return this.request({
221
+ method: 'GET',
222
+ path: `/v1/tenants/${id}`,
223
+ query: { withUsage },
224
+ });
225
+ }
226
+ async updateTenant(id, data) {
227
+ return this.request({
228
+ method: 'PATCH',
229
+ path: `/v1/tenants/${id}`,
230
+ body: data,
231
+ });
232
+ }
233
+ async deleteTenant(id) {
234
+ await this.request({
235
+ method: 'DELETE',
236
+ path: `/v1/tenants/${id}`,
237
+ });
238
+ }
239
+ async getTenantUsage(id) {
240
+ return this.request({
241
+ method: 'GET',
242
+ path: `/v1/tenants/${id}/usage`,
243
+ });
244
+ }
245
+ // ============ Users ============
246
+ async listUsers(options) {
247
+ const response = await this.request({
248
+ method: 'GET',
249
+ path: '/v1/users',
250
+ query: {
251
+ tenantId: options?.tenantId,
252
+ role: options?.role,
253
+ status: options?.status,
254
+ pageSize: 1000,
255
+ },
256
+ });
257
+ return response.items;
258
+ }
259
+ async createUser(data) {
260
+ return this.request({
261
+ method: 'POST',
262
+ path: '/v1/users',
263
+ body: data,
264
+ });
265
+ }
266
+ async getUser(id) {
267
+ return this.request({
268
+ method: 'GET',
269
+ path: `/v1/users/${id}`,
270
+ });
271
+ }
272
+ async updateUser(id, data) {
273
+ return this.request({
274
+ method: 'PUT',
275
+ path: `/v1/users/${id}`,
276
+ body: data,
277
+ });
278
+ }
279
+ async deleteUser(id) {
280
+ await this.request({
281
+ method: 'DELETE',
282
+ path: `/v1/users/${id}`,
283
+ });
284
+ }
285
+ async unlockUser(id) {
286
+ return this.request({
287
+ method: 'PUT',
288
+ path: `/v1/users/${id}`,
289
+ body: { status: 'active', failedAttempts: 0, lockedUntil: null },
290
+ });
291
+ }
292
+ async resetUserPassword(id, newPassword) {
293
+ return this.request({
294
+ method: 'POST',
295
+ path: `/v1/users/${id}/reset-password`,
296
+ body: { newPassword },
297
+ });
298
+ }
299
+ async disableUserTotp(id) {
300
+ return this.request({
301
+ method: 'POST',
302
+ path: `/v1/users/${id}/totp/disable`,
303
+ });
304
+ }
305
+ // ============ Superadmins ============
306
+ async listSuperadmins() {
307
+ const users = await this.listUsers({ role: 'superadmin' });
308
+ return users.map(u => ({
309
+ id: u.id,
310
+ username: u.username,
311
+ email: u.email,
312
+ status: u.status,
313
+ totpEnabled: u.totpEnabled,
314
+ failedAttempts: u.failedAttempts,
315
+ lockedUntil: u.lockedUntil,
316
+ lastLogin: u.lastLogin,
317
+ createdAt: u.createdAt,
318
+ }));
319
+ }
320
+ async createSuperadmin(data) {
321
+ return this.request({
322
+ method: 'POST',
323
+ path: '/v1/superadmins',
324
+ body: data,
325
+ });
326
+ }
327
+ async resetSuperadminPassword(username, password) {
328
+ return this.request({
329
+ method: 'POST',
330
+ path: `/v1/superadmins/${username}/password`,
331
+ body: { password },
332
+ });
333
+ }
334
+ async unlockSuperadmin(username) {
335
+ return this.request({
336
+ method: 'POST',
337
+ path: `/v1/superadmins/${username}/unlock`,
338
+ });
339
+ }
340
+ async disableSuperadmin(username) {
341
+ return this.request({
342
+ method: 'POST',
343
+ path: `/v1/superadmins/${username}/disable`,
344
+ });
345
+ }
346
+ async enableSuperadmin(username) {
347
+ return this.request({
348
+ method: 'POST',
349
+ path: `/v1/superadmins/${username}/enable`,
350
+ });
351
+ }
352
+ // ============ Lockdown ============
353
+ async getLockdownStatus() {
354
+ return this.request({
355
+ method: 'GET',
356
+ path: '/v1/admin/lockdown/status',
357
+ });
358
+ }
359
+ async triggerLockdown(level, reason) {
360
+ return this.request({
361
+ method: 'POST',
362
+ path: '/v1/admin/lockdown/trigger',
363
+ body: { level, reason },
364
+ });
365
+ }
366
+ async clearLockdown(reason) {
367
+ return this.request({
368
+ method: 'POST',
369
+ path: '/v1/admin/lockdown/clear',
370
+ body: { reason },
371
+ });
372
+ }
373
+ async getLockdownHistory(limit) {
374
+ const response = await this.request({
375
+ method: 'GET',
376
+ path: '/v1/admin/lockdown/history',
377
+ query: { limit: limit || 50 },
378
+ });
379
+ return response.items;
380
+ }
381
+ async getThreats(options) {
382
+ const response = await this.request({
383
+ method: 'GET',
384
+ path: '/v1/admin/lockdown/threats',
385
+ query: {
386
+ category: options?.category,
387
+ since: options?.since,
388
+ limit: options?.limit || 100,
389
+ },
390
+ });
391
+ return response.items;
392
+ }
393
+ // ============ Audit ============
394
+ async listAudit(options) {
395
+ const response = await this.request({
396
+ method: 'GET',
397
+ path: '/v1/audit',
398
+ query: {
399
+ client_cn: options?.user,
400
+ action: options?.action,
401
+ start_date: options?.startDate,
402
+ end_date: options?.endDate,
403
+ limit: options?.limit || 100,
404
+ },
405
+ });
406
+ return response.items;
407
+ }
408
+ async verifyAuditChain() {
409
+ return this.request({
410
+ method: 'GET',
411
+ path: '/v1/audit/verify',
412
+ });
413
+ }
414
+ async exportAudit(options) {
415
+ return this.request({
416
+ method: 'GET',
417
+ path: '/v1/audit',
418
+ query: {
419
+ format: options?.format || 'json',
420
+ start_date: options?.startDate,
421
+ end_date: options?.endDate,
422
+ limit: 10000,
423
+ },
424
+ });
425
+ }
426
+ // ============ API Keys (Independent, tenant-scoped) ============
427
+ async createApiKey(data) {
428
+ return this.request({
429
+ method: 'POST',
430
+ path: '/auth/api-keys',
431
+ query: data.tenantId ? { tenantId: data.tenantId } : undefined,
432
+ body: {
433
+ name: data.name,
434
+ description: data.description,
435
+ expiresInDays: data.expiresInDays,
436
+ permissions: data.permissions,
437
+ ipAllowlist: data.ipAllowlist,
438
+ conditions: data.conditions,
439
+ },
440
+ });
441
+ }
442
+ async listApiKeys(tenantId) {
443
+ return this.request({
444
+ method: 'GET',
445
+ path: '/auth/api-keys',
446
+ query: tenantId ? { tenantId } : undefined,
447
+ });
448
+ }
449
+ async getApiKey(id, tenantId) {
450
+ return this.request({
451
+ method: 'GET',
452
+ path: `/auth/api-keys/${id}`,
453
+ query: tenantId ? { tenantId } : undefined,
454
+ });
455
+ }
456
+ async deleteApiKey(id, tenantId) {
457
+ await this.request({
458
+ method: 'DELETE',
459
+ path: `/auth/api-keys/${id}`,
460
+ query: tenantId ? { tenantId } : undefined,
461
+ });
462
+ }
463
+ async rotateApiKey(id, name, tenantId) {
464
+ return this.request({
465
+ method: 'POST',
466
+ path: `/auth/api-keys/${id}/rotate`,
467
+ query: tenantId ? { tenantId } : undefined,
468
+ body: name ? { name } : {},
469
+ });
470
+ }
471
+ async updateApiKeyPermissions(id, permissions, tenantId) {
472
+ return this.request({
473
+ method: 'PATCH',
474
+ path: `/auth/api-keys/${id}/permissions`,
475
+ query: tenantId ? { tenantId } : undefined,
476
+ body: { permissions },
477
+ });
478
+ }
479
+ async updateApiKeyConditions(id, conditions, tenantId) {
480
+ const response = await this.request({
481
+ method: 'PATCH',
482
+ path: `/auth/api-keys/${id}/conditions`,
483
+ query: tenantId ? { tenantId } : undefined,
484
+ body: { conditions },
485
+ });
486
+ return response.apiKey;
487
+ }
488
+ async setApiKeyEnabled(id, enabled, tenantId) {
489
+ const response = await this.request({
490
+ method: 'PATCH',
491
+ path: `/auth/api-keys/${id}/enabled`,
492
+ query: tenantId ? { tenantId } : undefined,
493
+ body: { enabled },
494
+ });
495
+ return response.apiKey;
496
+ }
497
+ // =========================================================================
498
+ // Permissions API
499
+ // =========================================================================
500
+ /**
501
+ * Get all available permissions from the database
502
+ * This is the single source of truth for valid permission IDs
503
+ */
504
+ async getPermissions(category) {
505
+ return this.request({
506
+ method: 'GET',
507
+ path: '/v1/permissions',
508
+ query: category ? { category } : undefined,
509
+ });
510
+ }
511
+ /**
512
+ * Validate a list of permission IDs against the database
513
+ */
514
+ async validatePermissions(permissions) {
515
+ return this.request({
516
+ method: 'POST',
517
+ path: '/v1/permissions/validate',
518
+ body: { permissions },
519
+ });
520
+ }
521
+ async getApiKeyPolicies(id, tenantId) {
522
+ return this.request({
523
+ method: 'GET',
524
+ path: `/auth/api-keys/${id}/policies`,
525
+ query: tenantId ? { tenantId } : undefined,
526
+ });
527
+ }
528
+ async attachApiKeyPolicy(keyId, policyId, tenantId) {
529
+ return this.request({
530
+ method: 'POST',
531
+ path: `/auth/api-keys/${keyId}/policies/${policyId}`,
532
+ query: tenantId ? { tenantId } : undefined,
533
+ });
534
+ }
535
+ async detachApiKeyPolicy(keyId, policyId, tenantId) {
536
+ return this.request({
537
+ method: 'DELETE',
538
+ path: `/auth/api-keys/${keyId}/policies/${policyId}`,
539
+ query: tenantId ? { tenantId } : undefined,
540
+ });
541
+ }
542
+ async getApiKeySelf() {
543
+ return this.request({
544
+ method: 'GET',
545
+ path: '/auth/api-keys/self',
546
+ });
547
+ }
548
+ async rotateApiKeySelf(name) {
549
+ return this.request({
550
+ method: 'POST',
551
+ path: '/auth/api-keys/self/rotate',
552
+ body: name ? { name } : {},
553
+ });
554
+ }
555
+ // ============ ABAC Policies ============
556
+ async listPolicies(options) {
557
+ return this.request({
558
+ method: 'GET',
559
+ path: '/v1/policies',
560
+ query: {
561
+ tenantId: options?.tenantId,
562
+ enabled: options?.enabled,
563
+ effect: options?.effect,
564
+ search: options?.search,
565
+ page: options?.page,
566
+ pageSize: options?.pageSize || 100,
567
+ },
568
+ });
569
+ }
570
+ async getPolicy(id) {
571
+ return this.request({
572
+ method: 'GET',
573
+ path: `/v1/policies/${id}`,
574
+ });
575
+ }
576
+ async createPolicy(data) {
577
+ return this.request({
578
+ method: 'POST',
579
+ path: '/v1/policies',
580
+ body: data,
581
+ });
582
+ }
583
+ async updatePolicy(id, data) {
584
+ return this.request({
585
+ method: 'PATCH',
586
+ path: `/v1/policies/${id}`,
587
+ body: data,
588
+ });
589
+ }
590
+ async deletePolicy(id) {
591
+ await this.request({
592
+ method: 'DELETE',
593
+ path: `/v1/policies/${id}`,
594
+ });
595
+ }
596
+ async togglePolicy(id, enabled) {
597
+ return this.request({
598
+ method: 'POST',
599
+ path: `/v1/policies/${id}/toggle`,
600
+ body: { enabled },
601
+ });
602
+ }
603
+ async validatePolicy(policy) {
604
+ return this.request({
605
+ method: 'POST',
606
+ path: '/v1/policies/validate',
607
+ body: policy,
608
+ });
609
+ }
610
+ async getPolicyAttachments(policyId) {
611
+ return this.request({
612
+ method: 'GET',
613
+ path: `/v1/policies/${policyId}/attachments`,
614
+ });
615
+ }
616
+ async attachPolicyToUser(policyId, userId) {
617
+ return this.request({
618
+ method: 'POST',
619
+ path: `/v1/policies/${policyId}/attach/user`,
620
+ body: { userId },
621
+ });
622
+ }
623
+ async attachPolicyToRole(policyId, roleId) {
624
+ return this.request({
625
+ method: 'POST',
626
+ path: `/v1/policies/${policyId}/attach/role`,
627
+ body: { roleId },
628
+ });
629
+ }
630
+ async detachPolicyFromUser(policyId, userId) {
631
+ return this.request({
632
+ method: 'DELETE',
633
+ path: `/v1/policies/${policyId}/attach/user/${userId}`,
634
+ });
635
+ }
636
+ async detachPolicyFromRole(policyId, roleId) {
637
+ return this.request({
638
+ method: 'DELETE',
639
+ path: `/v1/policies/${policyId}/attach/role/${roleId}`,
640
+ });
641
+ }
642
+ async getUserPolicies(userId) {
643
+ const response = await this.request({
644
+ method: 'GET',
645
+ path: `/v1/users/${userId}/policies`,
646
+ });
647
+ return response.policies;
648
+ }
649
+ async getRolePolicies(roleId) {
650
+ const response = await this.request({
651
+ method: 'GET',
652
+ path: `/v1/roles/${roleId}/policies`,
653
+ });
654
+ return response.policies;
655
+ }
656
+ async testPolicy(request) {
657
+ return this.request({
658
+ method: 'POST',
659
+ path: '/v1/policies/test',
660
+ body: request,
661
+ });
662
+ }
663
+ // ============ Generic methods for arbitrary endpoints ============
664
+ /**
665
+ * Generic GET request
666
+ */
667
+ async get(path) {
668
+ return this.request({ method: 'GET', path });
669
+ }
670
+ /**
671
+ * Generic POST request
672
+ */
673
+ async post(path, body) {
674
+ return this.request({ method: 'POST', path, body });
675
+ }
676
+ /**
677
+ * Generic DELETE request
678
+ */
679
+ async delete(path) {
680
+ return this.request({ method: 'DELETE', path });
681
+ }
682
+ /**
683
+ * Generic PATCH request
684
+ */
685
+ async patch(path, body) {
686
+ return this.request({ method: 'PATCH', path, body });
687
+ }
688
+ /**
689
+ * Get WebSocket URL for a given endpoint path
690
+ */
691
+ getWebSocketUrl(wsPath) {
692
+ const url = new URL(this.baseUrl);
693
+ url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
694
+ url.pathname = wsPath;
695
+ return url.toString();
696
+ }
697
+ /**
698
+ * Get authentication headers for WebSocket connection
699
+ */
700
+ async getAuthHeaders() {
701
+ const headers = {};
702
+ if (hasApiKey()) {
703
+ headers['X-API-Key'] = getApiKey();
704
+ }
705
+ else {
706
+ const credentials = getCredentials();
707
+ if (credentials) {
708
+ // Check if token is expired and try to refresh
709
+ if (isTokenExpired() && credentials.refreshToken) {
710
+ await this.refreshToken();
711
+ }
712
+ const updatedCredentials = getCredentials();
713
+ if (updatedCredentials) {
714
+ headers['Authorization'] = `Bearer ${updatedCredentials.accessToken}`;
715
+ }
716
+ }
717
+ else if (hasEnvCredentials()) {
718
+ // Auto-login with env credentials
719
+ const envCreds = getEnvCredentials();
720
+ await this.login(envCreds.username, envCreds.password);
721
+ const newCredentials = getCredentials();
722
+ if (newCredentials) {
723
+ headers['Authorization'] = `Bearer ${newCredentials.accessToken}`;
724
+ }
725
+ }
726
+ }
727
+ return headers;
728
+ }
729
+ }
730
+ // Export singleton instance
731
+ export const client = new VaultClient();
732
+ // Export class for testing
733
+ export { VaultClient };
734
+ //# sourceMappingURL=client.js.map