sequoia-cli 0.3.0 → 0.3.1

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 (2) hide show
  1. package/dist/index.js +127 -22
  2. 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 imagePath = path4.join(imagesDir, filename);
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;
@@ -100491,13 +100542,13 @@ var loginCommand = import_cmd_ts4.command({
100491
100542
  },
100492
100543
  handler: async ({ logout, list }) => {
100493
100544
  if (list) {
100494
- const sessions = await listOAuthSessions();
100545
+ const sessions = await listOAuthSessionsWithHandles();
100495
100546
  if (sessions.length === 0) {
100496
100547
  R2.info("No OAuth sessions stored");
100497
100548
  } else {
100498
100549
  R2.info("OAuth sessions:");
100499
- for (const did2 of sessions) {
100500
- console.log(` - ${did2}`);
100550
+ for (const { did: did2, handle: handle2 } of sessions) {
100551
+ console.log(` - ${handle2 || did2} (${did2})`);
100501
100552
  }
100502
100553
  }
100503
100554
  return;
@@ -100591,12 +100642,11 @@ var loginCommand = import_cmd_ts4.command({
100591
100642
  }
100592
100643
  s.message("Completing authentication...");
100593
100644
  const { session } = await client.callback(new URLSearchParams(result.params));
100594
- let displayName = handle;
100595
- try {
100596
- displayName = handle.startsWith("did:") ? session.did : handle;
100597
- } catch {
100598
- displayName = session.did;
100645
+ const handleToStore = handle.startsWith("did:") ? undefined : handle;
100646
+ if (handleToStore) {
100647
+ await setOAuthHandle(session.did, handleToStore);
100599
100648
  }
100649
+ const displayName = handleToStore || session.did;
100600
100650
  s.stop(`Logged in as ${displayName}`);
100601
100651
  R2.success(`OAuth session saved to ${getOAuthStorePath()}`);
100602
100652
  R2.info("Your session will refresh automatically when needed.");
@@ -100727,23 +100777,51 @@ var publishCommand = import_cmd_ts5.command({
100727
100777
  R2.info(`Content directory: ${config.contentDir}`);
100728
100778
  let credentials = await loadCredentials(config.identity);
100729
100779
  if (!credentials) {
100730
- const identities = await listCredentials();
100780
+ const identities = await listAllCredentials();
100731
100781
  if (identities.length === 0) {
100732
- R2.error("No credentials found. Run 'sequoia auth' first.");
100782
+ R2.error("No credentials found. Run 'sequoia login' or 'sequoia auth' first.");
100733
100783
  R2.info("Or set ATP_IDENTIFIER and ATP_APP_PASSWORD environment variables.");
100734
100784
  process.exit(1);
100735
100785
  }
100786
+ const options = await Promise.all(identities.map(async (cred) => {
100787
+ if (cred.type === "oauth") {
100788
+ const handle = await getOAuthHandle(cred.id);
100789
+ return {
100790
+ value: cred.id,
100791
+ label: `${handle || cred.id} (OAuth)`
100792
+ };
100793
+ }
100794
+ return {
100795
+ value: cred.id,
100796
+ label: `${cred.id} (App Password)`
100797
+ };
100798
+ }));
100736
100799
  R2.info("Multiple identities found. Select one to use:");
100737
100800
  const selected = exitOnCancel(await qt({
100738
100801
  message: "Identity:",
100739
- options: identities.map((id) => ({ value: id, label: id }))
100802
+ options
100740
100803
  }));
100741
- credentials = await getCredentials(selected);
100804
+ const selectedCred = identities.find((c) => c.id === selected);
100805
+ if (selectedCred?.type === "oauth") {
100806
+ const session = await getOAuthSession(selected);
100807
+ if (session) {
100808
+ const handle = await getOAuthHandle(selected);
100809
+ credentials = {
100810
+ type: "oauth",
100811
+ did: selected,
100812
+ handle: handle || selected,
100813
+ pdsUrl: "https://bsky.social"
100814
+ };
100815
+ }
100816
+ } else {
100817
+ credentials = await getCredentials(selected);
100818
+ }
100742
100819
  if (!credentials) {
100743
100820
  R2.error("Failed to load selected credentials.");
100744
100821
  process.exit(1);
100745
100822
  }
100746
- R2.info(`Tip: Add "identity": "${selected}" to sequoia.json to use this by default.`);
100823
+ const displayId = credentials.type === "oauth" ? credentials.handle || credentials.did : credentials.identifier;
100824
+ R2.info(`Tip: Add "identity": "${displayId}" to sequoia.json to use this by default.`);
100747
100825
  }
100748
100826
  const contentDir = path10.isAbsolute(config.contentDir) ? config.contentDir : path10.join(configDir, config.contentDir);
100749
100827
  const imagesDir = config.imagesDir ? path10.isAbsolute(config.imagesDir) ? config.imagesDir : path10.join(configDir, config.imagesDir) : undefined;
@@ -100969,17 +101047,44 @@ var syncCommand = import_cmd_ts6.command({
100969
101047
  R2.info(`Publication: ${config.publicationUri}`);
100970
101048
  let credentials = await loadCredentials(config.identity);
100971
101049
  if (!credentials) {
100972
- const identities = await listCredentials();
101050
+ const identities = await listAllCredentials();
100973
101051
  if (identities.length === 0) {
100974
- R2.error("No credentials found. Run 'sequoia auth' first.");
101052
+ R2.error("No credentials found. Run 'sequoia login' or 'sequoia auth' first.");
100975
101053
  process.exit(1);
100976
101054
  }
101055
+ const options = await Promise.all(identities.map(async (cred) => {
101056
+ if (cred.type === "oauth") {
101057
+ const handle = await getOAuthHandle(cred.id);
101058
+ return {
101059
+ value: cred.id,
101060
+ label: `${handle || cred.id} (OAuth)`
101061
+ };
101062
+ }
101063
+ return {
101064
+ value: cred.id,
101065
+ label: `${cred.id} (App Password)`
101066
+ };
101067
+ }));
100977
101068
  R2.info("Multiple identities found. Select one to use:");
100978
101069
  const selected = exitOnCancel(await qt({
100979
101070
  message: "Identity:",
100980
- options: identities.map((id) => ({ value: id, label: id }))
101071
+ options
100981
101072
  }));
100982
- credentials = await getCredentials(selected);
101073
+ const selectedCred = identities.find((c) => c.id === selected);
101074
+ if (selectedCred?.type === "oauth") {
101075
+ const session = await getOAuthSession(selected);
101076
+ if (session) {
101077
+ const handle = await getOAuthHandle(selected);
101078
+ credentials = {
101079
+ type: "oauth",
101080
+ did: selected,
101081
+ handle: handle || selected,
101082
+ pdsUrl: "https://bsky.social"
101083
+ };
101084
+ }
101085
+ } else {
101086
+ credentials = await getCredentials(selected);
101087
+ }
100983
101088
  if (!credentials) {
100984
101089
  R2.error("Failed to load selected credentials.");
100985
101090
  process.exit(1);
@@ -101501,7 +101606,7 @@ Publish evergreen content to the ATmosphere
101501
101606
 
101502
101607
  > https://tangled.org/stevedylan.dev/sequoia
101503
101608
  `,
101504
- version: "0.3.0",
101609
+ version: "0.3.1",
101505
101610
  cmds: {
101506
101611
  auth: authCommand,
101507
101612
  init: initCommand,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sequoia-cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sequoia": "dist/index.js"