opensteer 0.6.1 → 0.6.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/cli/auth.cjs CHANGED
@@ -804,13 +804,10 @@ function createKeychainStore() {
804
804
  }
805
805
 
806
806
  // src/auth/machine-credential-store.ts
807
- var METADATA_VERSION = 1;
808
- var ACTIVE_TARGET_VERSION = 1;
807
+ var METADATA_VERSION = 2;
808
+ var ACTIVE_TARGET_VERSION = 2;
809
809
  var KEYCHAIN_SERVICE = "com.opensteer.cli.cloud";
810
810
  var KEYCHAIN_ACCOUNT_PREFIX = "machine:";
811
- var LEGACY_KEYCHAIN_ACCOUNT = "machine";
812
- var LEGACY_METADATA_FILE_NAME = "cli-login.json";
813
- var LEGACY_FALLBACK_SECRET_FILE_NAME = "cli-login.secret.json";
814
811
  var ACTIVE_TARGET_FILE_NAME = "cli-target.json";
815
812
  var MachineCredentialStore = class {
816
813
  authDir;
@@ -825,8 +822,11 @@ var MachineCredentialStore = class {
825
822
  this.warn = options.warn ?? (() => void 0);
826
823
  }
827
824
  readCloudCredential(target) {
828
- const slot = resolveCredentialSlot(this.authDir, target);
829
- return this.readCredentialSlot(slot, target) ?? this.readAndMigrateLegacyCredential(target);
825
+ const normalizedTarget = normalizeCloudCredentialTarget(target);
826
+ return this.readCredentialSlot(
827
+ resolveCredentialSlot(this.authDir, normalizedTarget),
828
+ normalizedTarget
829
+ );
830
830
  }
831
831
  writeCloudCredential(args) {
832
832
  const accessToken = args.accessToken.trim();
@@ -834,12 +834,8 @@ var MachineCredentialStore = class {
834
834
  if (!accessToken || !refreshToken2) {
835
835
  throw new Error("Cannot persist empty machine credential secrets.");
836
836
  }
837
- const baseUrl = normalizeCredentialUrl(args.baseUrl, "baseUrl");
838
- const siteUrl = normalizeCredentialUrl(args.siteUrl, "siteUrl");
839
- const slot = resolveCredentialSlot(this.authDir, {
840
- baseUrl,
841
- siteUrl
842
- });
837
+ const baseUrl = normalizeCredentialUrl(args.baseUrl);
838
+ const slot = resolveCredentialSlot(this.authDir, { baseUrl });
843
839
  ensureDirectory(this.authDir);
844
840
  const secretPayload = {
845
841
  accessToken,
@@ -866,7 +862,6 @@ var MachineCredentialStore = class {
866
862
  version: METADATA_VERSION,
867
863
  secretBackend,
868
864
  baseUrl,
869
- siteUrl,
870
865
  scope: args.scope,
871
866
  obtainedAt: args.obtainedAt,
872
867
  expiresAt: args.expiresAt,
@@ -878,23 +873,18 @@ var MachineCredentialStore = class {
878
873
  return readActiveCloudTargetMetadata(resolveActiveTargetPath(this.authDir));
879
874
  }
880
875
  writeActiveCloudTarget(target) {
881
- const baseUrl = normalizeCredentialUrl(target.baseUrl, "baseUrl");
882
- const siteUrl = normalizeCredentialUrl(target.siteUrl, "siteUrl");
876
+ const baseUrl = normalizeCredentialUrl(target.baseUrl);
883
877
  ensureDirectory(this.authDir);
884
878
  writeJsonFile(resolveActiveTargetPath(this.authDir), {
885
879
  version: ACTIVE_TARGET_VERSION,
886
880
  baseUrl,
887
- siteUrl,
888
881
  updatedAt: Date.now()
889
882
  });
890
883
  }
891
884
  clearCloudCredential(target) {
892
- this.clearCredentialSlot(resolveCredentialSlot(this.authDir, target));
893
- const legacySlot = resolveLegacyCredentialSlot(this.authDir);
894
- const legacyMetadata = readMetadata(legacySlot.metadataPath);
895
- if (legacyMetadata && matchesCredentialTarget(legacyMetadata, target)) {
896
- this.clearCredentialSlot(legacySlot);
897
- }
885
+ this.clearCredentialSlot(
886
+ resolveCredentialSlot(this.authDir, normalizeCloudCredentialTarget(target))
887
+ );
898
888
  }
899
889
  readCredentialSlot(slot, target) {
900
890
  const metadata = readMetadata(slot.metadataPath);
@@ -910,7 +900,6 @@ var MachineCredentialStore = class {
910
900
  }
911
901
  return {
912
902
  baseUrl: metadata.baseUrl,
913
- siteUrl: metadata.siteUrl,
914
903
  scope: metadata.scope,
915
904
  accessToken: secret.accessToken,
916
905
  refreshToken: secret.refreshToken,
@@ -918,16 +907,6 @@ var MachineCredentialStore = class {
918
907
  expiresAt: metadata.expiresAt
919
908
  };
920
909
  }
921
- readAndMigrateLegacyCredential(target) {
922
- const legacySlot = resolveLegacyCredentialSlot(this.authDir);
923
- const legacyCredential = this.readCredentialSlot(legacySlot, target);
924
- if (!legacyCredential) {
925
- return null;
926
- }
927
- this.writeCloudCredential(legacyCredential);
928
- this.clearCredentialSlot(legacySlot);
929
- return legacyCredential;
930
- }
931
910
  readSecret(slot, backend) {
932
911
  if (backend === "keychain" && this.keychain) {
933
912
  try {
@@ -968,9 +947,8 @@ function createMachineCredentialStore(options = {}) {
968
947
  return new MachineCredentialStore(options);
969
948
  }
970
949
  function resolveCredentialSlot(authDir, target) {
971
- const normalizedBaseUrl = normalizeCredentialUrl(target.baseUrl, "baseUrl");
972
- const normalizedSiteUrl = normalizeCredentialUrl(target.siteUrl, "siteUrl");
973
- const storageKey = (0, import_node_crypto.createHash)("sha256").update(`${normalizedBaseUrl}\0${normalizedSiteUrl}`).digest("hex").slice(0, 24);
950
+ const normalizedBaseUrl = normalizeCredentialUrl(target.baseUrl);
951
+ const storageKey = (0, import_node_crypto.createHash)("sha256").update(normalizedBaseUrl).digest("hex").slice(0, 24);
974
952
  return {
975
953
  keychainAccount: `${KEYCHAIN_ACCOUNT_PREFIX}${storageKey}`,
976
954
  metadataPath: import_node_path.default.join(authDir, `cli-login.${storageKey}.json`),
@@ -980,26 +958,24 @@ function resolveCredentialSlot(authDir, target) {
980
958
  )
981
959
  };
982
960
  }
983
- function resolveLegacyCredentialSlot(authDir) {
984
- return {
985
- keychainAccount: LEGACY_KEYCHAIN_ACCOUNT,
986
- metadataPath: import_node_path.default.join(authDir, LEGACY_METADATA_FILE_NAME),
987
- fallbackSecretPath: import_node_path.default.join(authDir, LEGACY_FALLBACK_SECRET_FILE_NAME)
988
- };
989
- }
990
961
  function resolveActiveTargetPath(authDir) {
991
962
  return import_node_path.default.join(authDir, ACTIVE_TARGET_FILE_NAME);
992
963
  }
993
964
  function matchesCredentialTarget(value, target) {
994
- return normalizeCredentialUrl(value.baseUrl, "baseUrl") === normalizeCredentialUrl(target.baseUrl, "baseUrl") && normalizeCredentialUrl(value.siteUrl, "siteUrl") === normalizeCredentialUrl(target.siteUrl, "siteUrl");
965
+ return normalizeCredentialUrl(value.baseUrl) === normalizeCredentialUrl(target.baseUrl);
995
966
  }
996
- function normalizeCredentialUrl(value, field) {
967
+ function normalizeCredentialUrl(value) {
997
968
  const normalized = stripTrailingSlashes(value.trim());
998
969
  if (!normalized) {
999
- throw new Error(`Cannot persist machine credential without ${field}.`);
970
+ throw new Error("Cannot persist machine credential without baseUrl.");
1000
971
  }
1001
972
  return normalized;
1002
973
  }
974
+ function normalizeCloudCredentialTarget(target) {
975
+ return {
976
+ baseUrl: normalizeCredentialUrl(target.baseUrl)
977
+ };
978
+ }
1003
979
  function resolveConfigDir(appName, env) {
1004
980
  if (process.platform === "win32") {
1005
981
  const appData = env.APPDATA?.trim() || import_node_path.default.join(import_node_os.default.homedir(), "AppData", "Roaming");
@@ -1038,7 +1014,6 @@ function readMetadata(filePath) {
1038
1014
  return null;
1039
1015
  }
1040
1016
  if (typeof parsed.baseUrl !== "string" || !parsed.baseUrl.trim()) return null;
1041
- if (typeof parsed.siteUrl !== "string" || !parsed.siteUrl.trim()) return null;
1042
1017
  if (!Array.isArray(parsed.scope)) return null;
1043
1018
  if (typeof parsed.obtainedAt !== "number") return null;
1044
1019
  if (typeof parsed.expiresAt !== "number") return null;
@@ -1047,7 +1022,6 @@ function readMetadata(filePath) {
1047
1022
  version: parsed.version,
1048
1023
  secretBackend: parsed.secretBackend,
1049
1024
  baseUrl: parsed.baseUrl,
1050
- siteUrl: parsed.siteUrl,
1051
1025
  scope: parsed.scope.filter(
1052
1026
  (value) => typeof value === "string"
1053
1027
  ),
@@ -1072,12 +1046,8 @@ function readActiveCloudTargetMetadata(filePath) {
1072
1046
  if (typeof parsed.baseUrl !== "string" || !parsed.baseUrl.trim()) {
1073
1047
  return null;
1074
1048
  }
1075
- if (typeof parsed.siteUrl !== "string" || !parsed.siteUrl.trim()) {
1076
- return null;
1077
- }
1078
1049
  return {
1079
- baseUrl: parsed.baseUrl,
1080
- siteUrl: parsed.siteUrl
1050
+ baseUrl: parsed.baseUrl
1081
1051
  };
1082
1052
  } catch {
1083
1053
  return null;
@@ -1102,14 +1072,13 @@ function readSecretFile(filePath) {
1102
1072
  return null;
1103
1073
  }
1104
1074
  try {
1105
- const raw = import_node_fs.default.readFileSync(filePath, "utf8");
1106
- return parseSecretPayload(raw);
1075
+ return parseSecretPayload(import_node_fs.default.readFileSync(filePath, "utf8"));
1107
1076
  } catch {
1108
1077
  return null;
1109
1078
  }
1110
1079
  }
1111
- function writeJsonFile(filePath, payload, options = {}) {
1112
- import_node_fs.default.writeFileSync(filePath, JSON.stringify(payload, null, 2), {
1080
+ function writeJsonFile(filePath, value, options = {}) {
1081
+ import_node_fs.default.writeFileSync(filePath, JSON.stringify(value, null, 2), {
1113
1082
  encoding: "utf8",
1114
1083
  mode: options.mode ?? 384
1115
1084
  });
@@ -1140,11 +1109,12 @@ Commands:
1140
1109
 
1141
1110
  Options:
1142
1111
  --base-url <url> Cloud API base URL (defaults to env or the last selected host)
1143
- --site-url <url> Cloud site URL for browser/device auth (defaults to env or the last selected host)
1144
1112
  --json JSON output (login prompts go to stderr)
1145
1113
  --no-browser Do not auto-open your default browser during login
1146
1114
  -h, --help Show this help
1147
1115
  `;
1116
+ var DEFAULT_AUTH_SITE_URL = "https://opensteer.com";
1117
+ var INTERNAL_AUTH_SITE_URL_ENV = "OPENSTEER_INTERNAL_AUTH_SITE_URL";
1148
1118
  function createDefaultDeps() {
1149
1119
  const env = process.env;
1150
1120
  return {
@@ -1196,13 +1166,6 @@ function parseAuthCommonArgs(rawArgs) {
1196
1166
  i = value.nextIndex;
1197
1167
  continue;
1198
1168
  }
1199
- if (arg === "--site-url") {
1200
- const value = readFlagValue(rawArgs, i, "--site-url");
1201
- if (!value.ok) return { args, error: value.error };
1202
- args.siteUrl = value.value;
1203
- i = value.nextIndex;
1204
- continue;
1205
- }
1206
1169
  return {
1207
1170
  args,
1208
1171
  error: `Unsupported option "${arg}".`
@@ -1272,16 +1235,19 @@ function resolveBaseUrl(provided, env) {
1272
1235
  assertSecureUrl(baseUrl, "--base-url");
1273
1236
  return baseUrl;
1274
1237
  }
1275
- function resolveSiteUrl(provided, baseUrl, env) {
1276
- const siteUrl = normalizeCloudBaseUrl(
1277
- (provided || env.OPENSTEER_CLOUD_SITE_URL || deriveSiteUrlFromBaseUrl(baseUrl)).trim()
1238
+ function resolveAuthSiteUrl(env) {
1239
+ const authSiteUrl = normalizeCloudBaseUrl(
1240
+ (env[INTERNAL_AUTH_SITE_URL_ENV] || DEFAULT_AUTH_SITE_URL).trim()
1241
+ );
1242
+ assertSecureUrl(
1243
+ authSiteUrl,
1244
+ `environment variable ${INTERNAL_AUTH_SITE_URL_ENV}`
1278
1245
  );
1279
- assertSecureUrl(siteUrl, "--site-url");
1280
- return siteUrl;
1246
+ return authSiteUrl;
1281
1247
  }
1282
- function hasExplicitCloudTargetSelection(providedBaseUrl, providedSiteUrl, env) {
1248
+ function hasExplicitCloudTargetSelection(providedBaseUrl, env) {
1283
1249
  return Boolean(
1284
- providedBaseUrl?.trim() || providedSiteUrl?.trim() || env.OPENSTEER_BASE_URL?.trim() || env.OPENSTEER_CLOUD_SITE_URL?.trim()
1250
+ providedBaseUrl?.trim() || env.OPENSTEER_BASE_URL?.trim()
1285
1251
  );
1286
1252
  }
1287
1253
  function readRememberedCloudTarget(store) {
@@ -1291,57 +1257,21 @@ function readRememberedCloudTarget(store) {
1291
1257
  }
1292
1258
  try {
1293
1259
  const baseUrl = normalizeCloudBaseUrl(activeTarget.baseUrl);
1294
- const siteUrl = normalizeCloudBaseUrl(activeTarget.siteUrl);
1295
1260
  assertSecureUrl(baseUrl, "--base-url");
1296
- assertSecureUrl(siteUrl, "--site-url");
1297
- return {
1298
- baseUrl,
1299
- siteUrl
1300
- };
1261
+ return { baseUrl };
1301
1262
  } catch {
1302
1263
  return null;
1303
1264
  }
1304
1265
  }
1305
- function resolveCloudTarget(args, env, store) {
1306
- if (!hasExplicitCloudTargetSelection(args.baseUrl, args.siteUrl, env)) {
1266
+ function resolveCloudTarget(args, env, store, options = {}) {
1267
+ if (options.allowRememberedTarget !== false && !hasExplicitCloudTargetSelection(args.baseUrl, env)) {
1307
1268
  const rememberedTarget = readRememberedCloudTarget(store);
1308
1269
  if (rememberedTarget) {
1309
1270
  return rememberedTarget;
1310
1271
  }
1311
1272
  }
1312
1273
  const baseUrl = resolveBaseUrl(args.baseUrl, env);
1313
- const siteUrl = resolveSiteUrl(args.siteUrl, baseUrl, env);
1314
- return {
1315
- baseUrl,
1316
- siteUrl
1317
- };
1318
- }
1319
- function deriveSiteUrlFromBaseUrl(baseUrl) {
1320
- let parsed;
1321
- try {
1322
- parsed = new URL(baseUrl);
1323
- } catch {
1324
- return "https://opensteer.com";
1325
- }
1326
- const hostname = parsed.hostname.toLowerCase();
1327
- if (hostname.startsWith("api.")) {
1328
- parsed.hostname = hostname.slice("api.".length);
1329
- parsed.pathname = "";
1330
- parsed.search = "";
1331
- parsed.hash = "";
1332
- return normalizeCloudBaseUrl(parsed.toString());
1333
- }
1334
- if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1") {
1335
- parsed.port = "3001";
1336
- parsed.pathname = "";
1337
- parsed.search = "";
1338
- parsed.hash = "";
1339
- return normalizeCloudBaseUrl(parsed.toString());
1340
- }
1341
- parsed.pathname = "";
1342
- parsed.search = "";
1343
- parsed.hash = "";
1344
- return normalizeCloudBaseUrl(parsed.toString());
1274
+ return { baseUrl };
1345
1275
  }
1346
1276
  function assertSecureUrl(value, flag) {
1347
1277
  let parsed;
@@ -1416,10 +1346,10 @@ function parseCliOauthError(error) {
1416
1346
  interval: typeof root.interval === "number" ? root.interval : void 0
1417
1347
  };
1418
1348
  }
1419
- async function startDeviceAuthorization(siteUrl, fetchFn) {
1349
+ async function startDeviceAuthorization(authSiteUrl, fetchFn) {
1420
1350
  const response = await postJson(
1421
1351
  fetchFn,
1422
- `${siteUrl}/api/cli-auth/device/start`,
1352
+ `${authSiteUrl}/api/cli-auth/device/start`,
1423
1353
  {
1424
1354
  scope: ["cloud:browser"]
1425
1355
  }
@@ -1429,24 +1359,24 @@ async function startDeviceAuthorization(siteUrl, fetchFn) {
1429
1359
  }
1430
1360
  return response;
1431
1361
  }
1432
- async function pollDeviceToken(siteUrl, deviceCode, fetchFn) {
1362
+ async function pollDeviceToken(authSiteUrl, deviceCode, fetchFn) {
1433
1363
  return await postJson(
1434
1364
  fetchFn,
1435
- `${siteUrl}/api/cli-auth/device/token`,
1365
+ `${authSiteUrl}/api/cli-auth/device/token`,
1436
1366
  {
1437
1367
  grant_type: "urn:ietf:params:oauth:grant-type:device_code",
1438
1368
  device_code: deviceCode
1439
1369
  }
1440
1370
  );
1441
1371
  }
1442
- async function refreshToken(siteUrl, refreshTokenValue, fetchFn) {
1443
- return await postJson(fetchFn, `${siteUrl}/api/cli-auth/token`, {
1372
+ async function refreshToken(authSiteUrl, refreshTokenValue, fetchFn) {
1373
+ return await postJson(fetchFn, `${authSiteUrl}/api/cli-auth/token`, {
1444
1374
  grant_type: "refresh_token",
1445
1375
  refresh_token: refreshTokenValue
1446
1376
  });
1447
1377
  }
1448
- async function revokeToken(siteUrl, refreshTokenValue, fetchFn) {
1449
- await postJson(fetchFn, `${siteUrl}/api/cli-auth/revoke`, {
1378
+ async function revokeToken(authSiteUrl, refreshTokenValue, fetchFn) {
1379
+ await postJson(fetchFn, `${authSiteUrl}/api/cli-auth/revoke`, {
1450
1380
  token: refreshTokenValue
1451
1381
  });
1452
1382
  }
@@ -1463,7 +1393,7 @@ async function openDefaultBrowser(url) {
1463
1393
  }
1464
1394
  }
1465
1395
  async function runDeviceLoginFlow(args) {
1466
- const start = await startDeviceAuthorization(args.siteUrl, args.fetchFn);
1396
+ const start = await startDeviceAuthorization(args.authSiteUrl, args.fetchFn);
1467
1397
  if (args.openBrowser) {
1468
1398
  args.writeProgress(
1469
1399
  "Opening your default browser for Opensteer CLI authentication.\n"
@@ -1508,7 +1438,7 @@ ${start.verification_uri_complete}
1508
1438
  await args.sleep(pollIntervalMs);
1509
1439
  try {
1510
1440
  const tokenPayload = await pollDeviceToken(
1511
- args.siteUrl,
1441
+ args.authSiteUrl,
1512
1442
  start.device_code,
1513
1443
  args.fetchFn
1514
1444
  );
@@ -1556,7 +1486,7 @@ ${start.verification_uri_complete}
1556
1486
  }
1557
1487
  async function refreshSavedCredential(saved, deps) {
1558
1488
  const tokenPayload = await refreshToken(
1559
- saved.siteUrl,
1489
+ resolveAuthSiteUrl(deps.env),
1560
1490
  saved.refreshToken,
1561
1491
  deps.fetchFn
1562
1492
  );
@@ -1569,7 +1499,6 @@ async function refreshSavedCredential(saved, deps) {
1569
1499
  };
1570
1500
  deps.store.writeCloudCredential({
1571
1501
  baseUrl: saved.baseUrl,
1572
- siteUrl: saved.siteUrl,
1573
1502
  scope: updated.scope,
1574
1503
  accessToken: updated.accessToken,
1575
1504
  refreshToken: updated.refreshToken,
@@ -1598,8 +1527,7 @@ async function ensureSavedCredentialIsFresh(saved, deps) {
1598
1527
  const oauth = parseCliOauthError(error.body);
1599
1528
  if (oauth?.error === "invalid_grant" || oauth?.error === "expired_token") {
1600
1529
  deps.store.clearCloudCredential({
1601
- baseUrl: saved.baseUrl,
1602
- siteUrl: saved.siteUrl
1530
+ baseUrl: saved.baseUrl
1603
1531
  });
1604
1532
  return null;
1605
1533
  }
@@ -1699,7 +1627,7 @@ async function ensureCloudCredentialsForCommand(options) {
1699
1627
  `);
1700
1628
  }
1701
1629
  });
1702
- const { baseUrl, siteUrl } = resolveCloudTarget(options, env, store);
1630
+ const { baseUrl } = resolveCloudTarget(options, env, store);
1703
1631
  const initialCredential = resolveCloudCredential({
1704
1632
  env,
1705
1633
  apiKeyFlag: options.apiKeyFlag,
@@ -1707,11 +1635,9 @@ async function ensureCloudCredentialsForCommand(options) {
1707
1635
  });
1708
1636
  let credential = initialCredential;
1709
1637
  if (!credential) {
1710
- const saved = store.readCloudCredential({
1711
- baseUrl,
1712
- siteUrl
1713
- });
1638
+ const saved = store.readCloudCredential({ baseUrl });
1714
1639
  const freshSaved = saved ? await ensureSavedCredentialIsFresh(saved, {
1640
+ env,
1715
1641
  fetchFn,
1716
1642
  store,
1717
1643
  now,
@@ -1729,7 +1655,7 @@ async function ensureCloudCredentialsForCommand(options) {
1729
1655
  if (!credential) {
1730
1656
  if (options.autoLoginIfNeeded && (options.interactive ?? false)) {
1731
1657
  const loggedIn = await runDeviceLoginFlow({
1732
- siteUrl,
1658
+ authSiteUrl: resolveAuthSiteUrl(env),
1733
1659
  fetchFn,
1734
1660
  writeProgress,
1735
1661
  openExternalUrl,
@@ -1739,7 +1665,6 @@ async function ensureCloudCredentialsForCommand(options) {
1739
1665
  });
1740
1666
  store.writeCloudCredential({
1741
1667
  baseUrl,
1742
- siteUrl,
1743
1668
  scope: loggedIn.scope,
1744
1669
  accessToken: loggedIn.accessToken,
1745
1670
  refreshToken: loggedIn.refreshToken,
@@ -1757,28 +1682,25 @@ async function ensureCloudCredentialsForCommand(options) {
1757
1682
  throw new Error(toAuthMissingMessage(options.commandName));
1758
1683
  }
1759
1684
  }
1760
- store.writeActiveCloudTarget({
1761
- baseUrl,
1762
- siteUrl
1763
- });
1685
+ store.writeActiveCloudTarget({ baseUrl });
1764
1686
  applyCloudCredentialToEnv(env, credential);
1765
1687
  env.OPENSTEER_BASE_URL = baseUrl;
1766
- env.OPENSTEER_CLOUD_SITE_URL = siteUrl;
1767
1688
  return {
1768
1689
  token: credential.token,
1769
1690
  authScheme: credential.authScheme,
1770
1691
  source: credential.source,
1771
1692
  kind: credential.kind,
1772
- baseUrl,
1773
- siteUrl
1693
+ baseUrl
1774
1694
  };
1775
1695
  }
1776
1696
  async function runLogin(args, deps) {
1777
- const { baseUrl, siteUrl } = resolveCloudTarget(args, deps.env, deps.store);
1697
+ const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store, {
1698
+ allowRememberedTarget: false
1699
+ });
1778
1700
  const writeProgress = args.json ? deps.writeStderr : deps.writeStdout;
1779
1701
  const browserOpenMode = describeBrowserOpenMode(args, deps);
1780
1702
  const login = await runDeviceLoginFlow({
1781
- siteUrl,
1703
+ authSiteUrl: resolveAuthSiteUrl(deps.env),
1782
1704
  fetchFn: deps.fetchFn,
1783
1705
  writeProgress,
1784
1706
  openExternalUrl: deps.openExternalUrl,
@@ -1789,22 +1711,17 @@ async function runLogin(args, deps) {
1789
1711
  });
1790
1712
  deps.store.writeCloudCredential({
1791
1713
  baseUrl,
1792
- siteUrl,
1793
1714
  scope: login.scope,
1794
1715
  accessToken: login.accessToken,
1795
1716
  refreshToken: login.refreshToken,
1796
1717
  obtainedAt: deps.now(),
1797
1718
  expiresAt: login.expiresAt
1798
1719
  });
1799
- deps.store.writeActiveCloudTarget({
1800
- baseUrl,
1801
- siteUrl
1802
- });
1720
+ deps.store.writeActiveCloudTarget({ baseUrl });
1803
1721
  if (args.json) {
1804
1722
  writeJsonLine(deps, {
1805
1723
  loggedIn: true,
1806
1724
  baseUrl,
1807
- siteUrl,
1808
1725
  expiresAt: login.expiresAt,
1809
1726
  scope: login.scope,
1810
1727
  authSource: "device"
@@ -1812,33 +1729,22 @@ async function runLogin(args, deps) {
1812
1729
  return 0;
1813
1730
  }
1814
1731
  writeHumanLine(deps, "Opensteer CLI login successful.");
1815
- writeHumanLine(deps, ` Site URL: ${siteUrl}`);
1816
1732
  writeHumanLine(deps, ` API Base URL: ${baseUrl}`);
1817
1733
  writeHumanLine(deps, ` Expires At: ${new Date(login.expiresAt).toISOString()}`);
1818
1734
  return 0;
1819
1735
  }
1820
1736
  async function runStatus(args, deps) {
1821
- const { baseUrl, siteUrl } = resolveCloudTarget(args, deps.env, deps.store);
1822
- deps.store.writeActiveCloudTarget({
1823
- baseUrl,
1824
- siteUrl
1825
- });
1826
- const saved = deps.store.readCloudCredential({
1827
- baseUrl,
1828
- siteUrl
1829
- });
1737
+ const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store);
1738
+ deps.store.writeActiveCloudTarget({ baseUrl });
1739
+ const saved = deps.store.readCloudCredential({ baseUrl });
1830
1740
  if (!saved) {
1831
1741
  if (args.json) {
1832
1742
  writeJsonLine(deps, {
1833
1743
  loggedIn: false,
1834
- baseUrl,
1835
- siteUrl
1744
+ baseUrl
1836
1745
  });
1837
1746
  } else {
1838
- writeHumanLine(
1839
- deps,
1840
- `Opensteer CLI is not logged in for ${siteUrl}.`
1841
- );
1747
+ writeHumanLine(deps, `Opensteer CLI is not logged in for ${baseUrl}.`);
1842
1748
  }
1843
1749
  return 0;
1844
1750
  }
@@ -1849,7 +1755,6 @@ async function runStatus(args, deps) {
1849
1755
  loggedIn: true,
1850
1756
  expired,
1851
1757
  baseUrl: saved.baseUrl,
1852
- siteUrl: saved.siteUrl,
1853
1758
  expiresAt: saved.expiresAt,
1854
1759
  scope: saved.scope
1855
1760
  });
@@ -1859,43 +1764,33 @@ async function runStatus(args, deps) {
1859
1764
  deps,
1860
1765
  expired ? "Opensteer CLI has a saved login, but the access token is expired." : "Opensteer CLI is logged in."
1861
1766
  );
1862
- writeHumanLine(deps, ` Site URL: ${saved.siteUrl}`);
1863
1767
  writeHumanLine(deps, ` API Base URL: ${saved.baseUrl}`);
1864
1768
  writeHumanLine(deps, ` Expires At: ${new Date(saved.expiresAt).toISOString()}`);
1865
1769
  return 0;
1866
1770
  }
1867
1771
  async function runLogout(args, deps) {
1868
- const { baseUrl, siteUrl } = resolveCloudTarget(args, deps.env, deps.store);
1869
- deps.store.writeActiveCloudTarget({
1870
- baseUrl,
1871
- siteUrl
1872
- });
1873
- const saved = deps.store.readCloudCredential({
1874
- baseUrl,
1875
- siteUrl
1876
- });
1772
+ const { baseUrl } = resolveCloudTarget(args, deps.env, deps.store);
1773
+ deps.store.writeActiveCloudTarget({ baseUrl });
1774
+ const saved = deps.store.readCloudCredential({ baseUrl });
1877
1775
  if (saved) {
1878
1776
  try {
1879
- await revokeToken(saved.siteUrl, saved.refreshToken, deps.fetchFn);
1777
+ await revokeToken(
1778
+ resolveAuthSiteUrl(deps.env),
1779
+ saved.refreshToken,
1780
+ deps.fetchFn
1781
+ );
1880
1782
  } catch {
1881
1783
  }
1882
1784
  }
1883
- deps.store.clearCloudCredential({
1884
- baseUrl,
1885
- siteUrl
1886
- });
1785
+ deps.store.clearCloudCredential({ baseUrl });
1887
1786
  if (args.json) {
1888
1787
  writeJsonLine(deps, {
1889
1788
  loggedOut: true,
1890
- baseUrl,
1891
- siteUrl
1789
+ baseUrl
1892
1790
  });
1893
1791
  return 0;
1894
1792
  }
1895
- writeHumanLine(
1896
- deps,
1897
- `Opensteer CLI login removed for ${siteUrl}.`
1898
- );
1793
+ writeHumanLine(deps, `Opensteer CLI login removed for ${baseUrl}.`);
1899
1794
  return 0;
1900
1795
  }
1901
1796
  async function runOpensteerAuthCli(rawArgs, overrideDeps = {}) {
@@ -3,7 +3,6 @@ import 'playwright';
3
3
 
4
4
  interface StoredMachineCloudCredential {
5
5
  baseUrl: string;
6
- siteUrl: string;
7
6
  scope: string[];
8
7
  accessToken: string;
9
8
  refreshToken: string;
@@ -12,7 +11,6 @@ interface StoredMachineCloudCredential {
12
11
  }
13
12
  interface WriteMachineCloudCredentialArgs {
14
13
  baseUrl: string;
15
- siteUrl: string;
16
14
  scope: string[];
17
15
  accessToken: string;
18
16
  refreshToken: string;
@@ -21,7 +19,6 @@ interface WriteMachineCloudCredentialArgs {
21
19
  }
22
20
  interface CloudCredentialStoreTarget {
23
21
  baseUrl: string;
24
- siteUrl: string;
25
22
  }
26
23
 
27
24
  type AuthFetchFn = (input: string, init?: RequestInit) => Promise<Response>;
@@ -39,7 +36,6 @@ interface EnsuredCloudAuthContext {
39
36
  source: 'flag' | 'env' | 'saved';
40
37
  kind: 'api-key' | 'access-token';
41
38
  baseUrl: string;
42
- siteUrl: string;
43
39
  }
44
40
  interface EnsureCloudCredentialsOptions {
45
41
  commandName: string;
@@ -48,7 +44,6 @@ interface EnsureCloudCredentialsOptions {
48
44
  apiKeyFlag?: string;
49
45
  accessTokenFlag?: string;
50
46
  baseUrl?: string;
51
- siteUrl?: string;
52
47
  interactive?: boolean;
53
48
  autoLoginIfNeeded?: boolean;
54
49
  writeProgress?: (message: string) => void;
@@ -86,7 +81,6 @@ interface AuthCliDeps {
86
81
  }
87
82
  interface AuthCommonArgs {
88
83
  baseUrl?: string;
89
- siteUrl?: string;
90
84
  json?: boolean;
91
85
  }
92
86
  interface AuthLoginArgs extends AuthCommonArgs {
@@ -3,7 +3,6 @@ import 'playwright';
3
3
 
4
4
  interface StoredMachineCloudCredential {
5
5
  baseUrl: string;
6
- siteUrl: string;
7
6
  scope: string[];
8
7
  accessToken: string;
9
8
  refreshToken: string;
@@ -12,7 +11,6 @@ interface StoredMachineCloudCredential {
12
11
  }
13
12
  interface WriteMachineCloudCredentialArgs {
14
13
  baseUrl: string;
15
- siteUrl: string;
16
14
  scope: string[];
17
15
  accessToken: string;
18
16
  refreshToken: string;
@@ -21,7 +19,6 @@ interface WriteMachineCloudCredentialArgs {
21
19
  }
22
20
  interface CloudCredentialStoreTarget {
23
21
  baseUrl: string;
24
- siteUrl: string;
25
22
  }
26
23
 
27
24
  type AuthFetchFn = (input: string, init?: RequestInit) => Promise<Response>;
@@ -39,7 +36,6 @@ interface EnsuredCloudAuthContext {
39
36
  source: 'flag' | 'env' | 'saved';
40
37
  kind: 'api-key' | 'access-token';
41
38
  baseUrl: string;
42
- siteUrl: string;
43
39
  }
44
40
  interface EnsureCloudCredentialsOptions {
45
41
  commandName: string;
@@ -48,7 +44,6 @@ interface EnsureCloudCredentialsOptions {
48
44
  apiKeyFlag?: string;
49
45
  accessTokenFlag?: string;
50
46
  baseUrl?: string;
51
- siteUrl?: string;
52
47
  interactive?: boolean;
53
48
  autoLoginIfNeeded?: boolean;
54
49
  writeProgress?: (message: string) => void;
@@ -86,7 +81,6 @@ interface AuthCliDeps {
86
81
  }
87
82
  interface AuthCommonArgs {
88
83
  baseUrl?: string;
89
- siteUrl?: string;
90
84
  json?: boolean;
91
85
  }
92
86
  interface AuthLoginArgs extends AuthCommonArgs {