sequoia-cli 0.3.0 → 0.3.2
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/index.js +178 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -99159,6 +99159,25 @@ async function deleteOAuthSession(did) {
|
|
|
99159
99159
|
function getOAuthStorePath() {
|
|
99160
99160
|
return OAUTH_FILE;
|
|
99161
99161
|
}
|
|
99162
|
+
async function setOAuthHandle(did, handle) {
|
|
99163
|
+
const store = await loadOAuthStore();
|
|
99164
|
+
if (!store.handles) {
|
|
99165
|
+
store.handles = {};
|
|
99166
|
+
}
|
|
99167
|
+
store.handles[did] = handle;
|
|
99168
|
+
await saveOAuthStore(store);
|
|
99169
|
+
}
|
|
99170
|
+
async function getOAuthHandle(did) {
|
|
99171
|
+
const store = await loadOAuthStore();
|
|
99172
|
+
return store.handles?.[did];
|
|
99173
|
+
}
|
|
99174
|
+
async function listOAuthSessionsWithHandles() {
|
|
99175
|
+
const store = await loadOAuthStore();
|
|
99176
|
+
return Object.keys(store.sessions).map((did) => ({
|
|
99177
|
+
did,
|
|
99178
|
+
handle: store.handles?.[did]
|
|
99179
|
+
}));
|
|
99180
|
+
}
|
|
99162
99181
|
|
|
99163
99182
|
// src/lib/oauth-client.ts
|
|
99164
99183
|
var CALLBACK_PORT = 4000;
|
|
@@ -99330,9 +99349,17 @@ async function uploadImage(agent, imagePath) {
|
|
|
99330
99349
|
}
|
|
99331
99350
|
}
|
|
99332
99351
|
async function resolveImagePath(ogImage, imagesDir, contentDir) {
|
|
99333
|
-
const filename = path4.basename(ogImage);
|
|
99334
99352
|
if (imagesDir) {
|
|
99335
|
-
const
|
|
99353
|
+
const imagesDirBaseName = path4.basename(imagesDir);
|
|
99354
|
+
const imagesDirIndex = ogImage.indexOf(imagesDirBaseName);
|
|
99355
|
+
let relativePath;
|
|
99356
|
+
if (imagesDirIndex !== -1) {
|
|
99357
|
+
const afterImagesDir = ogImage.substring(imagesDirIndex + imagesDirBaseName.length);
|
|
99358
|
+
relativePath = afterImagesDir.replace(/^[/\\]/, "");
|
|
99359
|
+
} else {
|
|
99360
|
+
relativePath = path4.basename(ogImage);
|
|
99361
|
+
}
|
|
99362
|
+
const imagePath = path4.join(imagesDir, relativePath);
|
|
99336
99363
|
if (await fileExists2(imagePath)) {
|
|
99337
99364
|
const stat2 = await fs3.stat(imagePath);
|
|
99338
99365
|
if (stat2.size > 0) {
|
|
@@ -99727,14 +99754,25 @@ async function tryLoadOAuthCredentials(profile) {
|
|
|
99727
99754
|
if (profile.startsWith("did:")) {
|
|
99728
99755
|
const session = await getOAuthSession(profile);
|
|
99729
99756
|
if (session) {
|
|
99757
|
+
const handle = await getOAuthHandle(profile);
|
|
99730
99758
|
return {
|
|
99731
99759
|
type: "oauth",
|
|
99732
99760
|
did: profile,
|
|
99733
|
-
handle: profile,
|
|
99761
|
+
handle: handle || profile,
|
|
99734
99762
|
pdsUrl: "https://bsky.social"
|
|
99735
99763
|
};
|
|
99736
99764
|
}
|
|
99737
99765
|
}
|
|
99766
|
+
const sessions = await listOAuthSessionsWithHandles();
|
|
99767
|
+
const match2 = sessions.find((s) => s.handle === profile);
|
|
99768
|
+
if (match2) {
|
|
99769
|
+
return {
|
|
99770
|
+
type: "oauth",
|
|
99771
|
+
did: match2.did,
|
|
99772
|
+
handle: match2.handle || match2.did,
|
|
99773
|
+
pdsUrl: "https://bsky.social"
|
|
99774
|
+
};
|
|
99775
|
+
}
|
|
99738
99776
|
return null;
|
|
99739
99777
|
}
|
|
99740
99778
|
async function loadCredentials(projectIdentity) {
|
|
@@ -99779,10 +99817,11 @@ async function loadCredentials(projectIdentity) {
|
|
|
99779
99817
|
if (oauthDids.length === 1 && oauthDids[0]) {
|
|
99780
99818
|
const session = await getOAuthSession(oauthDids[0]);
|
|
99781
99819
|
if (session) {
|
|
99820
|
+
const handle = await getOAuthHandle(oauthDids[0]);
|
|
99782
99821
|
return {
|
|
99783
99822
|
type: "oauth",
|
|
99784
99823
|
did: oauthDids[0],
|
|
99785
|
-
handle: oauthDids[0],
|
|
99824
|
+
handle: handle || oauthDids[0],
|
|
99786
99825
|
pdsUrl: "https://bsky.social"
|
|
99787
99826
|
};
|
|
99788
99827
|
}
|
|
@@ -99801,6 +99840,18 @@ async function listCredentials() {
|
|
|
99801
99840
|
const store = await loadCredentialsStore();
|
|
99802
99841
|
return Object.keys(store);
|
|
99803
99842
|
}
|
|
99843
|
+
async function listAllCredentials() {
|
|
99844
|
+
const store = await loadCredentialsStore();
|
|
99845
|
+
const oauthDids = await listOAuthSessions();
|
|
99846
|
+
const result = [];
|
|
99847
|
+
for (const id of Object.keys(store)) {
|
|
99848
|
+
result.push({ id, type: "app-password" });
|
|
99849
|
+
}
|
|
99850
|
+
for (const did of oauthDids) {
|
|
99851
|
+
result.push({ id: did, type: "oauth" });
|
|
99852
|
+
}
|
|
99853
|
+
return result;
|
|
99854
|
+
}
|
|
99804
99855
|
async function saveCredentials(credentials) {
|
|
99805
99856
|
const store = await loadCredentialsStore();
|
|
99806
99857
|
store[credentials.identifier] = credentials;
|
|
@@ -100074,6 +100125,43 @@ async function saveState(configDir, state) {
|
|
|
100074
100125
|
await fs5.writeFile(statePath, JSON.stringify(state, null, 2));
|
|
100075
100126
|
}
|
|
100076
100127
|
|
|
100128
|
+
// src/lib/credential-select.ts
|
|
100129
|
+
async function selectCredential(allCredentials) {
|
|
100130
|
+
const options = await Promise.all(allCredentials.map(async ({ id, type }) => {
|
|
100131
|
+
let label = id;
|
|
100132
|
+
if (type === "oauth") {
|
|
100133
|
+
const handle = await getOAuthHandle(id);
|
|
100134
|
+
label = handle ? `${handle} (${id})` : id;
|
|
100135
|
+
}
|
|
100136
|
+
return {
|
|
100137
|
+
value: { id, type },
|
|
100138
|
+
label: `${label} [${type}]`
|
|
100139
|
+
};
|
|
100140
|
+
}));
|
|
100141
|
+
const selected = exitOnCancel(await qt({
|
|
100142
|
+
message: "Multiple identities found. Select one:",
|
|
100143
|
+
options
|
|
100144
|
+
}));
|
|
100145
|
+
if (selected.type === "oauth") {
|
|
100146
|
+
const session = await getOAuthSession(selected.id);
|
|
100147
|
+
if (session) {
|
|
100148
|
+
const handle = await getOAuthHandle(selected.id);
|
|
100149
|
+
return {
|
|
100150
|
+
type: "oauth",
|
|
100151
|
+
did: selected.id,
|
|
100152
|
+
handle: handle || selected.id,
|
|
100153
|
+
pdsUrl: "https://bsky.social"
|
|
100154
|
+
};
|
|
100155
|
+
}
|
|
100156
|
+
} else {
|
|
100157
|
+
const creds = await getCredentials(selected.id);
|
|
100158
|
+
if (creds) {
|
|
100159
|
+
return creds;
|
|
100160
|
+
}
|
|
100161
|
+
}
|
|
100162
|
+
return null;
|
|
100163
|
+
}
|
|
100164
|
+
|
|
100077
100165
|
// src/commands/init.ts
|
|
100078
100166
|
async function fileExists5(filePath) {
|
|
100079
100167
|
try {
|
|
@@ -100202,10 +100290,21 @@ var initCommand = import_cmd_ts2.command({
|
|
|
100202
100290
|
onCancel();
|
|
100203
100291
|
}
|
|
100204
100292
|
let publicationUri;
|
|
100205
|
-
|
|
100293
|
+
let credentials = await loadCredentials();
|
|
100206
100294
|
if (publicationChoice === "create") {
|
|
100207
100295
|
if (!credentials) {
|
|
100208
|
-
|
|
100296
|
+
const allCredentials = await listAllCredentials();
|
|
100297
|
+
if (allCredentials.length > 1) {
|
|
100298
|
+
credentials = await selectCredential(allCredentials);
|
|
100299
|
+
} else if (allCredentials.length === 1) {
|
|
100300
|
+
credentials = await selectCredential(allCredentials);
|
|
100301
|
+
} else {
|
|
100302
|
+
R2.error("You must authenticate first. Run 'sequoia login' (recommended) or 'sequoia auth' before creating a publication.");
|
|
100303
|
+
process.exit(1);
|
|
100304
|
+
}
|
|
100305
|
+
}
|
|
100306
|
+
if (!credentials) {
|
|
100307
|
+
R2.error("Could not load credentials. Try running 'sequoia login' again to re-authenticate.");
|
|
100209
100308
|
process.exit(1);
|
|
100210
100309
|
}
|
|
100211
100310
|
const s = Ie();
|
|
@@ -100216,7 +100315,7 @@ var initCommand = import_cmd_ts2.command({
|
|
|
100216
100315
|
s.stop("Connected!");
|
|
100217
100316
|
} catch (_error) {
|
|
100218
100317
|
s.stop("Failed to connect");
|
|
100219
|
-
R2.error("Failed to connect.
|
|
100318
|
+
R2.error("Failed to connect. Try re-authenticating with 'sequoia login' or 'sequoia auth'.");
|
|
100220
100319
|
process.exit(1);
|
|
100221
100320
|
}
|
|
100222
100321
|
const publicationConfig = await Rt({
|
|
@@ -100491,13 +100590,13 @@ var loginCommand = import_cmd_ts4.command({
|
|
|
100491
100590
|
},
|
|
100492
100591
|
handler: async ({ logout, list }) => {
|
|
100493
100592
|
if (list) {
|
|
100494
|
-
const sessions = await
|
|
100593
|
+
const sessions = await listOAuthSessionsWithHandles();
|
|
100495
100594
|
if (sessions.length === 0) {
|
|
100496
100595
|
R2.info("No OAuth sessions stored");
|
|
100497
100596
|
} else {
|
|
100498
100597
|
R2.info("OAuth sessions:");
|
|
100499
|
-
for (const did2 of sessions) {
|
|
100500
|
-
console.log(` - ${did2}`);
|
|
100598
|
+
for (const { did: did2, handle: handle2 } of sessions) {
|
|
100599
|
+
console.log(` - ${handle2 || did2} (${did2})`);
|
|
100501
100600
|
}
|
|
100502
100601
|
}
|
|
100503
100602
|
return;
|
|
@@ -100591,12 +100690,11 @@ var loginCommand = import_cmd_ts4.command({
|
|
|
100591
100690
|
}
|
|
100592
100691
|
s.message("Completing authentication...");
|
|
100593
100692
|
const { session } = await client.callback(new URLSearchParams(result.params));
|
|
100594
|
-
|
|
100595
|
-
|
|
100596
|
-
|
|
100597
|
-
} catch {
|
|
100598
|
-
displayName = session.did;
|
|
100693
|
+
const handleToStore = handle.startsWith("did:") ? undefined : handle;
|
|
100694
|
+
if (handleToStore) {
|
|
100695
|
+
await setOAuthHandle(session.did, handleToStore);
|
|
100599
100696
|
}
|
|
100697
|
+
const displayName = handleToStore || session.did;
|
|
100600
100698
|
s.stop(`Logged in as ${displayName}`);
|
|
100601
100699
|
R2.success(`OAuth session saved to ${getOAuthStorePath()}`);
|
|
100602
100700
|
R2.info("Your session will refresh automatically when needed.");
|
|
@@ -100727,23 +100825,51 @@ var publishCommand = import_cmd_ts5.command({
|
|
|
100727
100825
|
R2.info(`Content directory: ${config.contentDir}`);
|
|
100728
100826
|
let credentials = await loadCredentials(config.identity);
|
|
100729
100827
|
if (!credentials) {
|
|
100730
|
-
const identities = await
|
|
100828
|
+
const identities = await listAllCredentials();
|
|
100731
100829
|
if (identities.length === 0) {
|
|
100732
|
-
R2.error("No credentials found. Run 'sequoia auth' first.");
|
|
100830
|
+
R2.error("No credentials found. Run 'sequoia login' or 'sequoia auth' first.");
|
|
100733
100831
|
R2.info("Or set ATP_IDENTIFIER and ATP_APP_PASSWORD environment variables.");
|
|
100734
100832
|
process.exit(1);
|
|
100735
100833
|
}
|
|
100834
|
+
const options = await Promise.all(identities.map(async (cred) => {
|
|
100835
|
+
if (cred.type === "oauth") {
|
|
100836
|
+
const handle = await getOAuthHandle(cred.id);
|
|
100837
|
+
return {
|
|
100838
|
+
value: cred.id,
|
|
100839
|
+
label: `${handle || cred.id} (OAuth)`
|
|
100840
|
+
};
|
|
100841
|
+
}
|
|
100842
|
+
return {
|
|
100843
|
+
value: cred.id,
|
|
100844
|
+
label: `${cred.id} (App Password)`
|
|
100845
|
+
};
|
|
100846
|
+
}));
|
|
100736
100847
|
R2.info("Multiple identities found. Select one to use:");
|
|
100737
100848
|
const selected = exitOnCancel(await qt({
|
|
100738
100849
|
message: "Identity:",
|
|
100739
|
-
options
|
|
100850
|
+
options
|
|
100740
100851
|
}));
|
|
100741
|
-
|
|
100852
|
+
const selectedCred = identities.find((c) => c.id === selected);
|
|
100853
|
+
if (selectedCred?.type === "oauth") {
|
|
100854
|
+
const session = await getOAuthSession(selected);
|
|
100855
|
+
if (session) {
|
|
100856
|
+
const handle = await getOAuthHandle(selected);
|
|
100857
|
+
credentials = {
|
|
100858
|
+
type: "oauth",
|
|
100859
|
+
did: selected,
|
|
100860
|
+
handle: handle || selected,
|
|
100861
|
+
pdsUrl: "https://bsky.social"
|
|
100862
|
+
};
|
|
100863
|
+
}
|
|
100864
|
+
} else {
|
|
100865
|
+
credentials = await getCredentials(selected);
|
|
100866
|
+
}
|
|
100742
100867
|
if (!credentials) {
|
|
100743
100868
|
R2.error("Failed to load selected credentials.");
|
|
100744
100869
|
process.exit(1);
|
|
100745
100870
|
}
|
|
100746
|
-
|
|
100871
|
+
const displayId = credentials.type === "oauth" ? credentials.handle || credentials.did : credentials.identifier;
|
|
100872
|
+
R2.info(`Tip: Add "identity": "${displayId}" to sequoia.json to use this by default.`);
|
|
100747
100873
|
}
|
|
100748
100874
|
const contentDir = path10.isAbsolute(config.contentDir) ? config.contentDir : path10.join(configDir, config.contentDir);
|
|
100749
100875
|
const imagesDir = config.imagesDir ? path10.isAbsolute(config.imagesDir) ? config.imagesDir : path10.join(configDir, config.imagesDir) : undefined;
|
|
@@ -100969,17 +101095,44 @@ var syncCommand = import_cmd_ts6.command({
|
|
|
100969
101095
|
R2.info(`Publication: ${config.publicationUri}`);
|
|
100970
101096
|
let credentials = await loadCredentials(config.identity);
|
|
100971
101097
|
if (!credentials) {
|
|
100972
|
-
const identities = await
|
|
101098
|
+
const identities = await listAllCredentials();
|
|
100973
101099
|
if (identities.length === 0) {
|
|
100974
|
-
R2.error("No credentials found. Run 'sequoia auth' first.");
|
|
101100
|
+
R2.error("No credentials found. Run 'sequoia login' or 'sequoia auth' first.");
|
|
100975
101101
|
process.exit(1);
|
|
100976
101102
|
}
|
|
101103
|
+
const options = await Promise.all(identities.map(async (cred) => {
|
|
101104
|
+
if (cred.type === "oauth") {
|
|
101105
|
+
const handle = await getOAuthHandle(cred.id);
|
|
101106
|
+
return {
|
|
101107
|
+
value: cred.id,
|
|
101108
|
+
label: `${handle || cred.id} (OAuth)`
|
|
101109
|
+
};
|
|
101110
|
+
}
|
|
101111
|
+
return {
|
|
101112
|
+
value: cred.id,
|
|
101113
|
+
label: `${cred.id} (App Password)`
|
|
101114
|
+
};
|
|
101115
|
+
}));
|
|
100977
101116
|
R2.info("Multiple identities found. Select one to use:");
|
|
100978
101117
|
const selected = exitOnCancel(await qt({
|
|
100979
101118
|
message: "Identity:",
|
|
100980
|
-
options
|
|
101119
|
+
options
|
|
100981
101120
|
}));
|
|
100982
|
-
|
|
101121
|
+
const selectedCred = identities.find((c) => c.id === selected);
|
|
101122
|
+
if (selectedCred?.type === "oauth") {
|
|
101123
|
+
const session = await getOAuthSession(selected);
|
|
101124
|
+
if (session) {
|
|
101125
|
+
const handle = await getOAuthHandle(selected);
|
|
101126
|
+
credentials = {
|
|
101127
|
+
type: "oauth",
|
|
101128
|
+
did: selected,
|
|
101129
|
+
handle: handle || selected,
|
|
101130
|
+
pdsUrl: "https://bsky.social"
|
|
101131
|
+
};
|
|
101132
|
+
}
|
|
101133
|
+
} else {
|
|
101134
|
+
credentials = await getCredentials(selected);
|
|
101135
|
+
}
|
|
100983
101136
|
if (!credentials) {
|
|
100984
101137
|
R2.error("Failed to load selected credentials.");
|
|
100985
101138
|
process.exit(1);
|
|
@@ -101501,7 +101654,7 @@ Publish evergreen content to the ATmosphere
|
|
|
101501
101654
|
|
|
101502
101655
|
> https://tangled.org/stevedylan.dev/sequoia
|
|
101503
101656
|
`,
|
|
101504
|
-
version: "0.3.
|
|
101657
|
+
version: "0.3.2",
|
|
101505
101658
|
cmds: {
|
|
101506
101659
|
auth: authCommand,
|
|
101507
101660
|
init: initCommand,
|