siftctl 0.54.0 → 0.56.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/dist/api.js +11 -0
- package/dist/cli.js +14 -4
- package/dist/fingerprint.js +2 -1
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -24,6 +24,17 @@ export async function capabilities() {
|
|
|
24
24
|
throw new ApiError(`Capabilities failed: ${res.status}`, res.status);
|
|
25
25
|
return (await res.json());
|
|
26
26
|
}
|
|
27
|
+
export async function groupStatus(token) {
|
|
28
|
+
const res = await request('/sync/status', { token });
|
|
29
|
+
if (res.status === 404)
|
|
30
|
+
return { groupFingerprint: null }; // server predates the endpoint
|
|
31
|
+
if (res.status === 401)
|
|
32
|
+
throw new ApiError('Unauthorized — token revoked or invalid; run `siftctl pair` again', 401);
|
|
33
|
+
if (!res.ok)
|
|
34
|
+
throw new ApiError(`Status failed: ${res.status}`, res.status);
|
|
35
|
+
const body = (await res.json());
|
|
36
|
+
return { groupFingerprint: typeof body.groupFingerprint === 'string' ? body.groupFingerprint : null };
|
|
37
|
+
}
|
|
27
38
|
export async function redeemToken(code) {
|
|
28
39
|
const res = await request('/sync/tokens/redeem', {
|
|
29
40
|
method: 'POST',
|
package/dist/cli.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
2
3
|
import { pathToFileURL } from 'node:url';
|
|
3
4
|
import { baseUrl, readToken, writeToken } from './config.js';
|
|
4
|
-
import { ApiError, capabilities, pull, push, redeemToken } from './api.js';
|
|
5
|
+
import { ApiError, capabilities, groupStatus, pull, push, redeemToken } from './api.js';
|
|
5
6
|
import { tokenFingerprint } from './fingerprint.js';
|
|
6
7
|
import { fetchItems } from './items.js';
|
|
7
8
|
const USAGE = `siftctl — control your Sift subscriptions
|
|
8
9
|
|
|
9
10
|
Usage:
|
|
10
11
|
siftctl pair <code> Redeem an agent pairing code from Sift Settings
|
|
11
|
-
siftctl status [--json] Show API status, base URL, and token fingerprint
|
|
12
|
+
siftctl status [--json] Show API status, base URL, group code, and token fingerprint
|
|
12
13
|
siftctl feeds [--json] List subscribed feeds
|
|
13
14
|
siftctl feed add <url> Subscribe to a feed
|
|
14
15
|
siftctl feed remove <url> --yes Unsubscribe from a feed
|
|
@@ -55,12 +56,21 @@ async function cmdStatus(json) {
|
|
|
55
56
|
const cap = await capabilities();
|
|
56
57
|
const token = readToken();
|
|
57
58
|
if (json) {
|
|
58
|
-
out({
|
|
59
|
+
out({
|
|
60
|
+
sync: cap.sync,
|
|
61
|
+
url: baseUrl(),
|
|
62
|
+
paired: token !== null,
|
|
63
|
+
groupFingerprint: token ? (await groupStatus(token)).groupFingerprint : null,
|
|
64
|
+
fingerprint: token ? await tokenFingerprint(token) : null,
|
|
65
|
+
});
|
|
59
66
|
return;
|
|
60
67
|
}
|
|
61
68
|
console.log(`Sync: ${cap.sync ? 'available' : 'unavailable'}`);
|
|
62
69
|
console.log(`URL: ${baseUrl()}`);
|
|
63
70
|
if (token) {
|
|
71
|
+
const group = (await groupStatus(token)).groupFingerprint;
|
|
72
|
+
if (group)
|
|
73
|
+
console.log(`Group: ${group}`);
|
|
64
74
|
console.log(`Paired: yes (fingerprint ${await tokenFingerprint(token)})`);
|
|
65
75
|
}
|
|
66
76
|
else {
|
|
@@ -227,7 +237,7 @@ export async function runCli(argv) {
|
|
|
227
237
|
return 1;
|
|
228
238
|
}
|
|
229
239
|
}
|
|
230
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
240
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) {
|
|
231
241
|
runCli(process.argv.slice(2)).then((code) => {
|
|
232
242
|
process.exitCode = code;
|
|
233
243
|
});
|
package/dist/fingerprint.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { webcrypto } from 'node:crypto';
|
|
1
2
|
/** Crockford base32 alphabet (0-9 and A-Z minus I, L, O, U). */
|
|
2
3
|
const CROCKFORD = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
|
3
4
|
/**
|
|
@@ -6,7 +7,7 @@ const CROCKFORD = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
|
|
6
7
|
* so `siftctl status` shows the same string as the Settings agents list.
|
|
7
8
|
*/
|
|
8
9
|
export async function tokenFingerprint(token) {
|
|
9
|
-
const digest = await
|
|
10
|
+
const digest = await webcrypto.subtle.digest('SHA-256', new TextEncoder().encode(token));
|
|
10
11
|
const bytes = new Uint8Array(digest);
|
|
11
12
|
const value = ((bytes[0] << 16) | (bytes[1] << 8) | bytes[2]) & 0xFFFFF;
|
|
12
13
|
return (CROCKFORD[(value >> 15) & 31] +
|
package/package.json
CHANGED