@lifestreamdynamics/vault-cli 1.3.4 → 1.3.6
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/dist/commands/analytics.js +10 -3
- package/dist/commands/audit.js +56 -2
- package/dist/commands/auth.js +9 -1
- package/dist/commands/booking.js +39 -23
- package/dist/commands/calendar.js +107 -52
- package/dist/commands/connectors.js +21 -1
- package/dist/commands/docs.js +65 -23
- package/dist/commands/hooks.js +46 -8
- package/dist/commands/keys.js +9 -2
- package/dist/commands/links.js +13 -4
- package/dist/commands/mfa.js +5 -1
- package/dist/commands/plugins.js +4 -3
- package/dist/commands/publish.js +25 -8
- package/dist/commands/search.js +7 -0
- package/dist/commands/shares.js +12 -3
- package/dist/commands/sync.js +37 -5
- package/dist/commands/user.js +13 -3
- package/dist/commands/vaults.js +6 -3
- package/dist/commands/versions.js +27 -9
- package/dist/commands/webhooks.js +39 -7
- package/dist/lib/credential-manager.js +8 -2
- package/dist/lib/keychain.js +13 -1
- package/dist/utils/flags.js +1 -1
- package/dist/utils/output.d.ts +4 -1
- package/dist/utils/output.js +15 -3
- package/dist/utils/resolve-vault.d.ts +8 -0
- package/dist/utils/resolve-vault.js +19 -0
- package/package.json +1 -1
|
@@ -2,16 +2,18 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { getClientAsync } from '../client.js';
|
|
3
3
|
import { addGlobalFlags, resolveFlags } from '../utils/flags.js';
|
|
4
4
|
import { createOutput, handleError } from '../utils/output.js';
|
|
5
|
+
import { resolveVaultId } from '../utils/resolve-vault.js';
|
|
5
6
|
export function registerWebhookCommands(program) {
|
|
6
7
|
const webhooks = program.command('webhooks').description('Manage vault webhooks');
|
|
7
8
|
addGlobalFlags(webhooks.command('list')
|
|
8
9
|
.description('List all webhooks for a vault')
|
|
9
|
-
.argument('<vaultId>', 'Vault ID'))
|
|
10
|
+
.argument('<vaultId>', 'Vault ID or slug'))
|
|
10
11
|
.action(async (vaultId, _opts) => {
|
|
11
12
|
const flags = resolveFlags(_opts);
|
|
12
13
|
const out = createOutput(flags);
|
|
13
14
|
out.startSpinner('Fetching webhooks...');
|
|
14
15
|
try {
|
|
16
|
+
vaultId = await resolveVaultId(vaultId);
|
|
15
17
|
const client = await getClientAsync();
|
|
16
18
|
const webhookList = await client.webhooks.list(vaultId);
|
|
17
19
|
out.stopSpinner();
|
|
@@ -42,18 +44,45 @@ export function registerWebhookCommands(program) {
|
|
|
42
44
|
});
|
|
43
45
|
addGlobalFlags(webhooks.command('create')
|
|
44
46
|
.description('Create a new webhook')
|
|
45
|
-
.argument('<vaultId>', 'Vault ID')
|
|
47
|
+
.argument('<vaultId>', 'Vault ID or slug')
|
|
46
48
|
.argument('<url>', 'Webhook endpoint URL')
|
|
47
|
-
.option('--events <events>', 'Comma-separated events (
|
|
49
|
+
.option('--events <events>', 'Comma-separated events (document.created, document.updated, document.deleted, document.moved, document.copied, or * for all)', 'document.created,document.updated,document.deleted')
|
|
50
|
+
.addHelpText('after', `
|
|
51
|
+
VALID EVENT NAMES
|
|
52
|
+
document.created Document was created
|
|
53
|
+
document.updated Document content was updated
|
|
54
|
+
document.deleted Document was deleted
|
|
55
|
+
document.moved Document was moved or renamed
|
|
56
|
+
document.copied Document was copied
|
|
57
|
+
* All events
|
|
58
|
+
|
|
59
|
+
EXAMPLES
|
|
60
|
+
lsvault webhooks create <vaultId> https://example.com/hook
|
|
61
|
+
lsvault webhooks create <vaultId> https://example.com/hook --events "document.created,document.deleted"
|
|
62
|
+
lsvault webhooks create <vaultId> https://example.com/hook --events "*"`))
|
|
48
63
|
.action(async (vaultId, url, _opts) => {
|
|
49
64
|
const flags = resolveFlags(_opts);
|
|
50
65
|
const out = createOutput(flags);
|
|
66
|
+
if (!/^https?:\/\//i.test(url)) {
|
|
67
|
+
out.error(`Invalid webhook URL "${url}". URL must start with http:// or https://`);
|
|
68
|
+
process.exitCode = 1;
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const VALID_EVENTS = ['document.created', 'document.updated', 'document.deleted', 'document.moved', 'document.copied', '*'];
|
|
72
|
+
const events = String(_opts.events || 'document.created,document.updated,document.deleted').split(',').map((e) => e.trim());
|
|
73
|
+
const invalid = events.filter(e => !VALID_EVENTS.includes(e));
|
|
74
|
+
if (invalid.length > 0) {
|
|
75
|
+
out.error(`Invalid event name(s): ${invalid.join(', ')}. Valid values: ${VALID_EVENTS.join(', ')}`);
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
51
79
|
out.startSpinner('Creating webhook...');
|
|
52
80
|
try {
|
|
81
|
+
vaultId = await resolveVaultId(vaultId);
|
|
53
82
|
const client = await getClientAsync();
|
|
54
83
|
const params = {
|
|
55
84
|
url,
|
|
56
|
-
events
|
|
85
|
+
events,
|
|
57
86
|
};
|
|
58
87
|
const webhook = await client.webhooks.create(vaultId, params);
|
|
59
88
|
out.stopSpinner();
|
|
@@ -79,7 +108,7 @@ export function registerWebhookCommands(program) {
|
|
|
79
108
|
});
|
|
80
109
|
addGlobalFlags(webhooks.command('update')
|
|
81
110
|
.description('Update a webhook')
|
|
82
|
-
.argument('<vaultId>', 'Vault ID')
|
|
111
|
+
.argument('<vaultId>', 'Vault ID or slug')
|
|
83
112
|
.argument('<webhookId>', 'Webhook ID')
|
|
84
113
|
.option('--url <url>', 'New webhook URL')
|
|
85
114
|
.option('--events <events>', 'Comma-separated events')
|
|
@@ -95,6 +124,7 @@ export function registerWebhookCommands(program) {
|
|
|
95
124
|
}
|
|
96
125
|
out.startSpinner('Updating webhook...');
|
|
97
126
|
try {
|
|
127
|
+
vaultId = await resolveVaultId(vaultId);
|
|
98
128
|
const client = await getClientAsync();
|
|
99
129
|
const params = {};
|
|
100
130
|
if (_opts.url)
|
|
@@ -118,7 +148,7 @@ export function registerWebhookCommands(program) {
|
|
|
118
148
|
});
|
|
119
149
|
addGlobalFlags(webhooks.command('delete')
|
|
120
150
|
.description('Delete a webhook')
|
|
121
|
-
.argument('<vaultId>', 'Vault ID')
|
|
151
|
+
.argument('<vaultId>', 'Vault ID or slug')
|
|
122
152
|
.argument('<webhookId>', 'Webhook ID')
|
|
123
153
|
.option('-y, --yes', 'Skip confirmation prompt'))
|
|
124
154
|
.action(async (vaultId, webhookId, _opts) => {
|
|
@@ -130,6 +160,7 @@ export function registerWebhookCommands(program) {
|
|
|
130
160
|
}
|
|
131
161
|
out.startSpinner('Deleting webhook...');
|
|
132
162
|
try {
|
|
163
|
+
vaultId = await resolveVaultId(vaultId);
|
|
133
164
|
const client = await getClientAsync();
|
|
134
165
|
await client.webhooks.delete(vaultId, webhookId);
|
|
135
166
|
out.success('Webhook deleted successfully', { id: webhookId, deleted: true });
|
|
@@ -140,13 +171,14 @@ export function registerWebhookCommands(program) {
|
|
|
140
171
|
});
|
|
141
172
|
addGlobalFlags(webhooks.command('deliveries')
|
|
142
173
|
.description('List recent deliveries for a webhook')
|
|
143
|
-
.argument('<vaultId>', 'Vault ID')
|
|
174
|
+
.argument('<vaultId>', 'Vault ID or slug')
|
|
144
175
|
.argument('<webhookId>', 'Webhook ID'))
|
|
145
176
|
.action(async (vaultId, webhookId, _opts) => {
|
|
146
177
|
const flags = resolveFlags(_opts);
|
|
147
178
|
const out = createOutput(flags);
|
|
148
179
|
out.startSpinner('Fetching deliveries...');
|
|
149
180
|
try {
|
|
181
|
+
vaultId = await resolveVaultId(vaultId);
|
|
150
182
|
const client = await getClientAsync();
|
|
151
183
|
const deliveries = await client.webhooks.listDeliveries(vaultId, webhookId);
|
|
152
184
|
out.stopSpinner();
|
|
@@ -69,8 +69,14 @@ export function createCredentialManager(options = {}) {
|
|
|
69
69
|
async saveCredentials(config) {
|
|
70
70
|
// Prefer keychain if available
|
|
71
71
|
if (await keychain.isAvailable()) {
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
try {
|
|
73
|
+
await keychain.saveCredentials(config);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Keychain reported available but failed to save — fall through
|
|
78
|
+
// to encrypted config silently.
|
|
79
|
+
}
|
|
74
80
|
}
|
|
75
81
|
// Fall back to encrypted config
|
|
76
82
|
encryptedConfig.saveCredentials(config, passphrase);
|
package/dist/lib/keychain.js
CHANGED
|
@@ -9,7 +9,19 @@ const ACCOUNT_REFRESH_TOKEN = 'refresh-token';
|
|
|
9
9
|
*/
|
|
10
10
|
async function loadKeytar() {
|
|
11
11
|
try {
|
|
12
|
-
|
|
12
|
+
const mod = await import('keytar');
|
|
13
|
+
// CJS-in-ESM interop: keytar is a native CJS addon, so dynamic import
|
|
14
|
+
// wraps it as { default: { getPassword, setPassword, ... } }.
|
|
15
|
+
const resolved = (mod.default && typeof mod.default.getPassword === 'function')
|
|
16
|
+
? mod.default
|
|
17
|
+
: mod;
|
|
18
|
+
// Validate that the resolved module has the methods we need
|
|
19
|
+
if (typeof resolved.getPassword !== 'function' ||
|
|
20
|
+
typeof resolved.setPassword !== 'function' ||
|
|
21
|
+
typeof resolved.deletePassword !== 'function') {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return resolved;
|
|
13
25
|
}
|
|
14
26
|
catch {
|
|
15
27
|
return null;
|
package/dist/utils/flags.js
CHANGED
|
@@ -5,7 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
*/
|
|
6
6
|
export function addGlobalFlags(cmd) {
|
|
7
7
|
return cmd
|
|
8
|
-
.option('-o, --output <format>', 'Output format: text, json, table (default: auto)')
|
|
8
|
+
.option('-o, --output <format>', 'Output format: text, json, table (default: auto — text for TTY, json for pipes)')
|
|
9
9
|
.option('-v, --verbose', 'Verbose output (debug info)')
|
|
10
10
|
.option('-q, --quiet', 'Minimal output (errors only)')
|
|
11
11
|
.option('--no-color', 'Disable colored output')
|
package/dist/utils/output.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GlobalFlags } from './flags.js';
|
|
1
|
+
import type { GlobalFlags, OutputFormat } from './flags.js';
|
|
2
2
|
/**
|
|
3
3
|
* Column definition for table output.
|
|
4
4
|
*/
|
|
@@ -41,8 +41,11 @@ export declare class Output {
|
|
|
41
41
|
debug(message: string): void;
|
|
42
42
|
/**
|
|
43
43
|
* Print an error message to stderr.
|
|
44
|
+
* When output format is json, writes a JSON error envelope instead of colored text.
|
|
44
45
|
*/
|
|
45
46
|
error(message: string): void;
|
|
47
|
+
/** Expose the current output format (for error handlers that need it). */
|
|
48
|
+
get format(): OutputFormat;
|
|
46
49
|
/**
|
|
47
50
|
* Print a warning message to stderr.
|
|
48
51
|
*/
|
package/dist/utils/output.js
CHANGED
|
@@ -67,9 +67,19 @@ export class Output {
|
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Print an error message to stderr.
|
|
70
|
+
* When output format is json, writes a JSON error envelope instead of colored text.
|
|
70
71
|
*/
|
|
71
72
|
error(message) {
|
|
72
|
-
|
|
73
|
+
if (this.flags.output === 'json') {
|
|
74
|
+
process.stderr.write(JSON.stringify({ error: true, message }) + '\n');
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
process.stderr.write(chalk.red(message) + '\n');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Expose the current output format (for error handlers that need it). */
|
|
81
|
+
get format() {
|
|
82
|
+
return this.flags.output;
|
|
73
83
|
}
|
|
74
84
|
/**
|
|
75
85
|
* Print a warning message to stderr.
|
|
@@ -107,14 +117,16 @@ export class Output {
|
|
|
107
117
|
*/
|
|
108
118
|
list(data, options) {
|
|
109
119
|
if (data.length === 0) {
|
|
120
|
+
if (this.flags.quiet)
|
|
121
|
+
return;
|
|
110
122
|
if (this.flags.output === 'json') {
|
|
111
123
|
process.stdout.write('[]\n');
|
|
112
124
|
return;
|
|
113
125
|
}
|
|
114
|
-
if (options?.emptyMessage
|
|
126
|
+
if (options?.emptyMessage) {
|
|
115
127
|
this.status(options.emptyMessage);
|
|
116
128
|
}
|
|
117
|
-
else
|
|
129
|
+
else {
|
|
118
130
|
process.stdout.write('No results found.\n');
|
|
119
131
|
}
|
|
120
132
|
return;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accepts either a vault UUID or a vault slug. If a UUID is given it is
|
|
3
|
+
* returned unchanged. If a slug is given, the vault list is fetched and the
|
|
4
|
+
* matching vault's ID is returned.
|
|
5
|
+
*
|
|
6
|
+
* @throws {Error} If the slug does not match any vault.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveVaultId(idOrSlug: string): Promise<string>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getClientAsync } from '../client.js';
|
|
2
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3
|
+
/**
|
|
4
|
+
* Accepts either a vault UUID or a vault slug. If a UUID is given it is
|
|
5
|
+
* returned unchanged. If a slug is given, the vault list is fetched and the
|
|
6
|
+
* matching vault's ID is returned.
|
|
7
|
+
*
|
|
8
|
+
* @throws {Error} If the slug does not match any vault.
|
|
9
|
+
*/
|
|
10
|
+
export async function resolveVaultId(idOrSlug) {
|
|
11
|
+
if (UUID_RE.test(idOrSlug))
|
|
12
|
+
return idOrSlug;
|
|
13
|
+
const client = await getClientAsync();
|
|
14
|
+
const vaults = await client.vaults.list();
|
|
15
|
+
const match = vaults.find(v => v.slug === idOrSlug);
|
|
16
|
+
if (!match)
|
|
17
|
+
throw new Error(`Vault not found: "${idOrSlug}"`);
|
|
18
|
+
return match.id;
|
|
19
|
+
}
|