opensteer 0.6.2 → 0.6.3

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.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  isCloudModeEnabledForRootDir,
5
5
  parseOpensteerAuthArgs,
6
6
  runOpensteerAuthCli
7
- } from "../chunk-7RMY26CM.js";
8
- import "../chunk-WDRMHPWL.js";
7
+ } from "../chunk-SCNX4NN3.js";
8
+ import "../chunk-KE35RQOJ.js";
9
9
  export {
10
10
  ensureCloudCredentialsForCommand,
11
11
  ensureCloudCredentialsForOpenCommand,
@@ -659,6 +659,65 @@ function toJsonSafeValue(value, seen) {
659
659
  return void 0;
660
660
  }
661
661
 
662
+ // src/cloud/credential-selection.ts
663
+ function selectCloudCredential(options) {
664
+ const apiKey = normalizeNonEmptyString(options.apiKey);
665
+ const accessToken = normalizeNonEmptyString(options.accessToken);
666
+ if (apiKey) {
667
+ if (options.authScheme === "bearer") {
668
+ return {
669
+ apiKey,
670
+ authScheme: "bearer",
671
+ kind: "access-token",
672
+ token: apiKey,
673
+ compatibilityBearerApiKey: true
674
+ };
675
+ }
676
+ return {
677
+ apiKey,
678
+ authScheme: "api-key",
679
+ kind: "api-key",
680
+ token: apiKey
681
+ };
682
+ }
683
+ if (accessToken) {
684
+ return {
685
+ accessToken,
686
+ authScheme: "bearer",
687
+ kind: "access-token",
688
+ token: accessToken
689
+ };
690
+ }
691
+ return null;
692
+ }
693
+ function selectCloudCredentialByPrecedence(layers, authScheme) {
694
+ for (const layer of layers) {
695
+ const hasApiKey = layer.hasApiKey ?? Object.prototype.hasOwnProperty.call(layer, "apiKey");
696
+ const hasAccessToken = layer.hasAccessToken ?? Object.prototype.hasOwnProperty.call(layer, "accessToken");
697
+ if (!hasApiKey && !hasAccessToken) {
698
+ continue;
699
+ }
700
+ return {
701
+ source: layer.source,
702
+ apiKey: layer.apiKey,
703
+ accessToken: layer.accessToken,
704
+ hasApiKey,
705
+ hasAccessToken,
706
+ credential: selectCloudCredential({
707
+ apiKey: layer.apiKey,
708
+ accessToken: layer.accessToken,
709
+ authScheme: layer.authScheme ?? authScheme
710
+ })
711
+ };
712
+ }
713
+ return null;
714
+ }
715
+ function normalizeNonEmptyString(value) {
716
+ if (typeof value !== "string") return void 0;
717
+ const normalized = value.trim();
718
+ return normalized.length ? normalized : void 0;
719
+ }
720
+
662
721
  // src/storage/namespace.ts
663
722
  var import_path = __toESM(require("path"), 1);
664
723
  var DEFAULT_NAMESPACE = "default";
@@ -983,11 +1042,6 @@ function normalizeCloudOptions(value) {
983
1042
  }
984
1043
  return value;
985
1044
  }
986
- function normalizeNonEmptyString(value) {
987
- if (typeof value !== "string") return void 0;
988
- const normalized = value.trim();
989
- return normalized.length ? normalized : void 0;
990
- }
991
1045
  function parseCloudEnabled(value, source) {
992
1046
  if (value == null) return void 0;
993
1047
  if (typeof value === "boolean") return value;
@@ -996,6 +1050,18 @@ function parseCloudEnabled(value, source) {
996
1050
  `Invalid ${source} value "${String(value)}". Use true, false, or a cloud options object.`
997
1051
  );
998
1052
  }
1053
+ function resolveCloudCredentialFields(selectedLayer) {
1054
+ const credential = selectedLayer?.credential;
1055
+ if (!credential) return {};
1056
+ if (credential.kind === "api-key" || credential.compatibilityBearerApiKey === true && selectedLayer?.source !== "env") {
1057
+ return {
1058
+ apiKey: credential.token
1059
+ };
1060
+ }
1061
+ return {
1062
+ accessToken: credential.token
1063
+ };
1064
+ }
999
1065
  function resolveCloudSelection(config, env = process.env) {
1000
1066
  const configCloud = parseCloudEnabled(config.cloud, "cloud");
1001
1067
  if (configCloud !== void 0) {
@@ -1032,6 +1098,9 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1032
1098
  });
1033
1099
  assertNoLegacyAiConfig(".opensteer/config.json", fileConfig);
1034
1100
  assertNoLegacyRuntimeConfig(".opensteer/config.json", fileConfig);
1101
+ const fileCloudOptions = normalizeCloudOptions(fileConfig.cloud);
1102
+ const fileHasCloudApiKey = hasOwn(fileCloudOptions, "apiKey");
1103
+ const fileHasCloudAccessToken = hasOwn(fileCloudOptions, "accessToken");
1035
1104
  const fileRootDir = typeof fileConfig.storage?.rootDir === "string" ? fileConfig.storage.rootDir : void 0;
1036
1105
  const envRootDir = input.storage?.rootDir ?? fileRootDir ?? initialRootDir;
1037
1106
  const env = resolveEnv(envRootDir, {
@@ -1070,13 +1139,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1070
1139
  const envAccessTokenRaw = resolveOpensteerAccessToken(env);
1071
1140
  const envBaseUrl = resolveOpensteerBaseUrl(env);
1072
1141
  const envAuthScheme = resolveOpensteerAuthScheme(env);
1073
- if (envApiKey && envAccessTokenRaw) {
1074
- throw new Error(
1075
- "OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
1076
- );
1077
- }
1078
- const envAccessToken = envAccessTokenRaw || (envAuthScheme === "bearer" ? envApiKey : void 0);
1079
- const envApiCredential = envAuthScheme === "bearer" && !envAccessTokenRaw ? void 0 : envApiKey;
1080
1142
  const envCloudProfileId = resolveOpensteerCloudProfileId(env);
1081
1143
  const envCloudProfileReuseIfActive = resolveOpensteerCloudProfileReuseIfActive(env);
1082
1144
  const envCloudAnnounce = parseCloudAnnounce(
@@ -1105,11 +1167,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1105
1167
  const inputHasCloudBaseUrl = Boolean(
1106
1168
  inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
1107
1169
  );
1108
- if (normalizeNonEmptyString(inputCloudOptions?.apiKey) && normalizeNonEmptyString(inputCloudOptions?.accessToken)) {
1109
- throw new Error(
1110
- "cloud.apiKey and cloud.accessToken are mutually exclusive. Set only one."
1111
- );
1112
- }
1113
1170
  const cloudSelection = resolveCloudSelection({
1114
1171
  cloud: resolved.cloud
1115
1172
  }, env);
@@ -1120,11 +1177,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1120
1177
  accessToken: resolvedCloudAccessTokenRaw,
1121
1178
  ...resolvedCloudRest
1122
1179
  } = resolvedCloud;
1123
- if (normalizeNonEmptyString(resolvedCloudApiKeyRaw) && normalizeNonEmptyString(resolvedCloudAccessTokenRaw)) {
1124
- throw new Error(
1125
- "Cloud config cannot include both apiKey and accessToken at the same time."
1126
- );
1127
- }
1128
1180
  const resolvedCloudBrowserProfile = normalizeCloudBrowserProfileOptions(
1129
1181
  resolvedCloud.browserProfile,
1130
1182
  "resolved.cloud.browserProfile"
@@ -1136,25 +1188,40 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1136
1188
  const browserProfile = inputCloudBrowserProfile ?? envCloudBrowserProfile ?? resolvedCloudBrowserProfile;
1137
1189
  let authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedCloud.authScheme, "cloud.authScheme") ?? "api-key";
1138
1190
  const announce = inputCloudAnnounce ?? envCloudAnnounce ?? parseCloudAnnounce(resolvedCloud.announce, "cloud.announce") ?? "always";
1139
- const credentialOverriddenByInput = inputHasCloudApiKey || inputHasCloudAccessToken;
1140
- let apiKey = normalizeNonEmptyString(resolvedCloudApiKeyRaw);
1141
- let accessToken = normalizeNonEmptyString(resolvedCloudAccessTokenRaw);
1142
- if (!credentialOverriddenByInput) {
1143
- if (envAccessToken) {
1144
- accessToken = envAccessToken;
1145
- apiKey = void 0;
1146
- } else if (envApiCredential) {
1147
- apiKey = envApiCredential;
1148
- accessToken = void 0;
1149
- }
1150
- }
1191
+ const selectedCredentialLayer = selectCloudCredentialByPrecedence(
1192
+ [
1193
+ {
1194
+ source: "input",
1195
+ apiKey: inputCloudOptions?.apiKey,
1196
+ accessToken: inputCloudOptions?.accessToken,
1197
+ hasApiKey: inputHasCloudApiKey,
1198
+ hasAccessToken: inputHasCloudAccessToken
1199
+ },
1200
+ {
1201
+ source: "env",
1202
+ apiKey: envApiKey,
1203
+ accessToken: envAccessTokenRaw,
1204
+ hasApiKey: envApiKey !== void 0,
1205
+ hasAccessToken: envAccessTokenRaw !== void 0
1206
+ },
1207
+ {
1208
+ source: "file",
1209
+ apiKey: fileCloudOptions?.apiKey,
1210
+ accessToken: fileCloudOptions?.accessToken,
1211
+ hasApiKey: fileHasCloudApiKey,
1212
+ hasAccessToken: fileHasCloudAccessToken
1213
+ }
1214
+ ],
1215
+ authScheme
1216
+ );
1217
+ const { apiKey, accessToken } = resolveCloudCredentialFields(selectedCredentialLayer);
1151
1218
  if (accessToken) {
1152
1219
  authScheme = "bearer";
1153
1220
  }
1154
1221
  resolved.cloud = {
1155
1222
  ...resolvedCloudRest,
1156
- ...inputHasCloudApiKey ? { apiKey: resolvedCloudApiKeyRaw } : apiKey ? { apiKey } : {},
1157
- ...inputHasCloudAccessToken ? { accessToken: resolvedCloudAccessTokenRaw } : accessToken ? { accessToken } : {},
1223
+ ...apiKey ? { apiKey } : selectedCredentialLayer?.hasApiKey && !accessToken ? { apiKey: selectedCredentialLayer.apiKey } : {},
1224
+ ...accessToken ? { accessToken } : selectedCredentialLayer?.hasAccessToken && !apiKey ? { accessToken: selectedCredentialLayer.accessToken } : {},
1158
1225
  authScheme,
1159
1226
  announce,
1160
1227
  ...browserProfile ? { browserProfile } : {}
@@ -11780,30 +11847,20 @@ var Opensteer = class _Opensteer {
11780
11847
  this.pool = new BrowserPool(resolved.browser || {});
11781
11848
  if (cloudSelection.cloud) {
11782
11849
  const cloudConfig = resolved.cloud && typeof resolved.cloud === "object" ? resolved.cloud : void 0;
11783
- const apiKey = cloudConfig?.apiKey?.trim();
11784
- const accessToken = cloudConfig?.accessToken?.trim();
11785
- if (apiKey && accessToken) {
11786
- throw new Error(
11787
- "Cloud mode cannot use both cloud.apiKey and cloud.accessToken. Set only one credential."
11788
- );
11789
- }
11790
- let credential = "";
11791
- let authScheme = cloudConfig?.authScheme ?? "api-key";
11792
- if (accessToken) {
11793
- credential = accessToken;
11794
- authScheme = "bearer";
11795
- } else if (apiKey) {
11796
- credential = apiKey;
11797
- }
11850
+ const credential = selectCloudCredential({
11851
+ apiKey: cloudConfig?.apiKey,
11852
+ accessToken: cloudConfig?.accessToken,
11853
+ authScheme: cloudConfig?.authScheme
11854
+ });
11798
11855
  if (!credential) {
11799
11856
  throw new Error(
11800
11857
  "Cloud mode requires credentials via cloud.apiKey/cloud.accessToken or OPENSTEER_API_KEY/OPENSTEER_ACCESS_TOKEN."
11801
11858
  );
11802
11859
  }
11803
11860
  this.cloud = createCloudRuntimeState(
11804
- credential,
11861
+ credential.token,
11805
11862
  cloudConfig?.baseUrl,
11806
- authScheme
11863
+ credential.authScheme
11807
11864
  );
11808
11865
  } else {
11809
11866
  this.cloud = null;
@@ -14691,59 +14748,21 @@ var import_open = __toESM(require("open"), 1);
14691
14748
 
14692
14749
  // src/auth/credential-resolver.ts
14693
14750
  function resolveCloudCredential(options) {
14694
- const flagApiKey = normalizeToken(options.apiKeyFlag);
14695
- const flagAccessToken = normalizeToken(options.accessTokenFlag);
14696
- if (flagApiKey && flagAccessToken) {
14697
- throw new Error("--api-key and --access-token are mutually exclusive.");
14698
- }
14699
- if (flagAccessToken) {
14700
- return {
14701
- kind: "access-token",
14702
- source: "flag",
14703
- token: flagAccessToken,
14704
- authScheme: "bearer"
14705
- };
14706
- }
14707
- if (flagApiKey) {
14708
- return {
14709
- kind: "api-key",
14710
- source: "flag",
14711
- token: flagApiKey,
14712
- authScheme: "api-key"
14713
- };
14751
+ const flagCredential = selectCloudCredential({
14752
+ apiKey: options.apiKeyFlag,
14753
+ accessToken: options.accessTokenFlag
14754
+ });
14755
+ if (flagCredential) {
14756
+ return toResolvedCloudCredential("flag", flagCredential);
14714
14757
  }
14715
14758
  const envAuthScheme = parseEnvAuthScheme(options.env.OPENSTEER_AUTH_SCHEME);
14716
- const envApiKey = normalizeToken(options.env.OPENSTEER_API_KEY);
14717
- const envAccessToken = normalizeToken(options.env.OPENSTEER_ACCESS_TOKEN);
14718
- if (envApiKey && envAccessToken) {
14719
- throw new Error(
14720
- "OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
14721
- );
14722
- }
14723
- if (envAccessToken) {
14724
- return {
14725
- kind: "access-token",
14726
- source: "env",
14727
- token: envAccessToken,
14728
- authScheme: "bearer"
14729
- };
14730
- }
14731
- if (envApiKey) {
14732
- if (envAuthScheme === "bearer") {
14733
- return {
14734
- kind: "access-token",
14735
- source: "env",
14736
- token: envApiKey,
14737
- authScheme: "bearer",
14738
- compatibilityBearerApiKey: true
14739
- };
14740
- }
14741
- return {
14742
- kind: "api-key",
14743
- source: "env",
14744
- token: envApiKey,
14745
- authScheme: envAuthScheme ?? "api-key"
14746
- };
14759
+ const envCredential = selectCloudCredential({
14760
+ apiKey: options.env.OPENSTEER_API_KEY,
14761
+ accessToken: options.env.OPENSTEER_ACCESS_TOKEN,
14762
+ authScheme: envAuthScheme
14763
+ });
14764
+ if (envCredential) {
14765
+ return toResolvedCloudCredential("env", envCredential);
14747
14766
  }
14748
14767
  return null;
14749
14768
  }
@@ -14773,6 +14792,23 @@ function normalizeToken(value) {
14773
14792
  const normalized = value.trim();
14774
14793
  return normalized.length ? normalized : void 0;
14775
14794
  }
14795
+ function toResolvedCloudCredential(source, credential) {
14796
+ if (credential.compatibilityBearerApiKey) {
14797
+ return {
14798
+ kind: credential.kind,
14799
+ source,
14800
+ token: credential.token,
14801
+ authScheme: credential.authScheme,
14802
+ compatibilityBearerApiKey: true
14803
+ };
14804
+ }
14805
+ return {
14806
+ kind: credential.kind,
14807
+ source,
14808
+ token: credential.token,
14809
+ authScheme: credential.authScheme
14810
+ };
14811
+ }
14776
14812
 
14777
14813
  // src/auth/machine-credential-store.ts
14778
14814
  var import_node_crypto2 = require("crypto");
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  BrowserProfileClient
3
- } from "../chunk-WJI7TGBQ.js";
3
+ } from "../chunk-FTKWQ6X3.js";
4
4
  import {
5
5
  ensureCloudCredentialsForCommand
6
- } from "../chunk-7RMY26CM.js";
6
+ } from "../chunk-SCNX4NN3.js";
7
7
  import {
8
8
  Opensteer,
9
9
  expandHome,
10
10
  loadCookiesFromLocalProfileDir
11
- } from "../chunk-F2VDVOJO.js";
11
+ } from "../chunk-3OMXCBPD.js";
12
12
  import {
13
13
  resolveConfigWithEnv
14
- } from "../chunk-WDRMHPWL.js";
14
+ } from "../chunk-KE35RQOJ.js";
15
15
  import "../chunk-3H5RRIMZ.js";
16
16
 
17
17
  // src/cli/profile.ts
@@ -1210,6 +1210,65 @@ function toJsonSafeValue(value, seen) {
1210
1210
  return void 0;
1211
1211
  }
1212
1212
 
1213
+ // src/cloud/credential-selection.ts
1214
+ function selectCloudCredential(options) {
1215
+ const apiKey = normalizeNonEmptyString(options.apiKey);
1216
+ const accessToken = normalizeNonEmptyString(options.accessToken);
1217
+ if (apiKey) {
1218
+ if (options.authScheme === "bearer") {
1219
+ return {
1220
+ apiKey,
1221
+ authScheme: "bearer",
1222
+ kind: "access-token",
1223
+ token: apiKey,
1224
+ compatibilityBearerApiKey: true
1225
+ };
1226
+ }
1227
+ return {
1228
+ apiKey,
1229
+ authScheme: "api-key",
1230
+ kind: "api-key",
1231
+ token: apiKey
1232
+ };
1233
+ }
1234
+ if (accessToken) {
1235
+ return {
1236
+ accessToken,
1237
+ authScheme: "bearer",
1238
+ kind: "access-token",
1239
+ token: accessToken
1240
+ };
1241
+ }
1242
+ return null;
1243
+ }
1244
+ function selectCloudCredentialByPrecedence(layers, authScheme) {
1245
+ for (const layer of layers) {
1246
+ const hasApiKey = layer.hasApiKey ?? Object.prototype.hasOwnProperty.call(layer, "apiKey");
1247
+ const hasAccessToken = layer.hasAccessToken ?? Object.prototype.hasOwnProperty.call(layer, "accessToken");
1248
+ if (!hasApiKey && !hasAccessToken) {
1249
+ continue;
1250
+ }
1251
+ return {
1252
+ source: layer.source,
1253
+ apiKey: layer.apiKey,
1254
+ accessToken: layer.accessToken,
1255
+ hasApiKey,
1256
+ hasAccessToken,
1257
+ credential: selectCloudCredential({
1258
+ apiKey: layer.apiKey,
1259
+ accessToken: layer.accessToken,
1260
+ authScheme: layer.authScheme ?? authScheme
1261
+ })
1262
+ };
1263
+ }
1264
+ return null;
1265
+ }
1266
+ function normalizeNonEmptyString(value) {
1267
+ if (typeof value !== "string") return void 0;
1268
+ const normalized = value.trim();
1269
+ return normalized.length ? normalized : void 0;
1270
+ }
1271
+
1213
1272
  // src/storage/namespace.ts
1214
1273
  var import_path2 = __toESM(require("path"), 1);
1215
1274
  var DEFAULT_NAMESPACE = "default";
@@ -1534,11 +1593,6 @@ function normalizeCloudOptions(value) {
1534
1593
  }
1535
1594
  return value;
1536
1595
  }
1537
- function normalizeNonEmptyString(value) {
1538
- if (typeof value !== "string") return void 0;
1539
- const normalized = value.trim();
1540
- return normalized.length ? normalized : void 0;
1541
- }
1542
1596
  function parseCloudEnabled(value, source) {
1543
1597
  if (value == null) return void 0;
1544
1598
  if (typeof value === "boolean") return value;
@@ -1547,6 +1601,18 @@ function parseCloudEnabled(value, source) {
1547
1601
  `Invalid ${source} value "${String(value)}". Use true, false, or a cloud options object.`
1548
1602
  );
1549
1603
  }
1604
+ function resolveCloudCredentialFields(selectedLayer) {
1605
+ const credential = selectedLayer?.credential;
1606
+ if (!credential) return {};
1607
+ if (credential.kind === "api-key" || credential.compatibilityBearerApiKey === true && selectedLayer?.source !== "env") {
1608
+ return {
1609
+ apiKey: credential.token
1610
+ };
1611
+ }
1612
+ return {
1613
+ accessToken: credential.token
1614
+ };
1615
+ }
1550
1616
  function resolveCloudSelection(config, env = process.env) {
1551
1617
  const configCloud = parseCloudEnabled(config.cloud, "cloud");
1552
1618
  if (configCloud !== void 0) {
@@ -1583,6 +1649,9 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1583
1649
  });
1584
1650
  assertNoLegacyAiConfig(".opensteer/config.json", fileConfig);
1585
1651
  assertNoLegacyRuntimeConfig(".opensteer/config.json", fileConfig);
1652
+ const fileCloudOptions = normalizeCloudOptions(fileConfig.cloud);
1653
+ const fileHasCloudApiKey = hasOwn(fileCloudOptions, "apiKey");
1654
+ const fileHasCloudAccessToken = hasOwn(fileCloudOptions, "accessToken");
1586
1655
  const fileRootDir = typeof fileConfig.storage?.rootDir === "string" ? fileConfig.storage.rootDir : void 0;
1587
1656
  const envRootDir = input.storage?.rootDir ?? fileRootDir ?? initialRootDir;
1588
1657
  const env = resolveEnv(envRootDir, {
@@ -1621,13 +1690,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1621
1690
  const envAccessTokenRaw = resolveOpensteerAccessToken(env);
1622
1691
  const envBaseUrl = resolveOpensteerBaseUrl(env);
1623
1692
  const envAuthScheme = resolveOpensteerAuthScheme(env);
1624
- if (envApiKey && envAccessTokenRaw) {
1625
- throw new Error(
1626
- "OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
1627
- );
1628
- }
1629
- const envAccessToken = envAccessTokenRaw || (envAuthScheme === "bearer" ? envApiKey : void 0);
1630
- const envApiCredential = envAuthScheme === "bearer" && !envAccessTokenRaw ? void 0 : envApiKey;
1631
1693
  const envCloudProfileId = resolveOpensteerCloudProfileId(env);
1632
1694
  const envCloudProfileReuseIfActive = resolveOpensteerCloudProfileReuseIfActive(env);
1633
1695
  const envCloudAnnounce = parseCloudAnnounce(
@@ -1656,11 +1718,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1656
1718
  const inputHasCloudBaseUrl = Boolean(
1657
1719
  inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
1658
1720
  );
1659
- if (normalizeNonEmptyString(inputCloudOptions?.apiKey) && normalizeNonEmptyString(inputCloudOptions?.accessToken)) {
1660
- throw new Error(
1661
- "cloud.apiKey and cloud.accessToken are mutually exclusive. Set only one."
1662
- );
1663
- }
1664
1721
  const cloudSelection = resolveCloudSelection({
1665
1722
  cloud: resolved.cloud
1666
1723
  }, env);
@@ -1671,11 +1728,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1671
1728
  accessToken: resolvedCloudAccessTokenRaw,
1672
1729
  ...resolvedCloudRest
1673
1730
  } = resolvedCloud;
1674
- if (normalizeNonEmptyString(resolvedCloudApiKeyRaw) && normalizeNonEmptyString(resolvedCloudAccessTokenRaw)) {
1675
- throw new Error(
1676
- "Cloud config cannot include both apiKey and accessToken at the same time."
1677
- );
1678
- }
1679
1731
  const resolvedCloudBrowserProfile = normalizeCloudBrowserProfileOptions(
1680
1732
  resolvedCloud.browserProfile,
1681
1733
  "resolved.cloud.browserProfile"
@@ -1687,25 +1739,40 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1687
1739
  const browserProfile = inputCloudBrowserProfile ?? envCloudBrowserProfile ?? resolvedCloudBrowserProfile;
1688
1740
  let authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedCloud.authScheme, "cloud.authScheme") ?? "api-key";
1689
1741
  const announce = inputCloudAnnounce ?? envCloudAnnounce ?? parseCloudAnnounce(resolvedCloud.announce, "cloud.announce") ?? "always";
1690
- const credentialOverriddenByInput = inputHasCloudApiKey || inputHasCloudAccessToken;
1691
- let apiKey = normalizeNonEmptyString(resolvedCloudApiKeyRaw);
1692
- let accessToken = normalizeNonEmptyString(resolvedCloudAccessTokenRaw);
1693
- if (!credentialOverriddenByInput) {
1694
- if (envAccessToken) {
1695
- accessToken = envAccessToken;
1696
- apiKey = void 0;
1697
- } else if (envApiCredential) {
1698
- apiKey = envApiCredential;
1699
- accessToken = void 0;
1700
- }
1701
- }
1742
+ const selectedCredentialLayer = selectCloudCredentialByPrecedence(
1743
+ [
1744
+ {
1745
+ source: "input",
1746
+ apiKey: inputCloudOptions?.apiKey,
1747
+ accessToken: inputCloudOptions?.accessToken,
1748
+ hasApiKey: inputHasCloudApiKey,
1749
+ hasAccessToken: inputHasCloudAccessToken
1750
+ },
1751
+ {
1752
+ source: "env",
1753
+ apiKey: envApiKey,
1754
+ accessToken: envAccessTokenRaw,
1755
+ hasApiKey: envApiKey !== void 0,
1756
+ hasAccessToken: envAccessTokenRaw !== void 0
1757
+ },
1758
+ {
1759
+ source: "file",
1760
+ apiKey: fileCloudOptions?.apiKey,
1761
+ accessToken: fileCloudOptions?.accessToken,
1762
+ hasApiKey: fileHasCloudApiKey,
1763
+ hasAccessToken: fileHasCloudAccessToken
1764
+ }
1765
+ ],
1766
+ authScheme
1767
+ );
1768
+ const { apiKey, accessToken } = resolveCloudCredentialFields(selectedCredentialLayer);
1702
1769
  if (accessToken) {
1703
1770
  authScheme = "bearer";
1704
1771
  }
1705
1772
  resolved.cloud = {
1706
1773
  ...resolvedCloudRest,
1707
- ...inputHasCloudApiKey ? { apiKey: resolvedCloudApiKeyRaw } : apiKey ? { apiKey } : {},
1708
- ...inputHasCloudAccessToken ? { accessToken: resolvedCloudAccessTokenRaw } : accessToken ? { accessToken } : {},
1774
+ ...apiKey ? { apiKey } : selectedCredentialLayer?.hasApiKey && !accessToken ? { apiKey: selectedCredentialLayer.apiKey } : {},
1775
+ ...accessToken ? { accessToken } : selectedCredentialLayer?.hasAccessToken && !apiKey ? { accessToken: selectedCredentialLayer.accessToken } : {},
1709
1776
  authScheme,
1710
1777
  announce,
1711
1778
  ...browserProfile ? { browserProfile } : {}
@@ -11220,30 +11287,20 @@ var Opensteer = class _Opensteer {
11220
11287
  this.pool = new BrowserPool(resolved.browser || {});
11221
11288
  if (cloudSelection.cloud) {
11222
11289
  const cloudConfig = resolved.cloud && typeof resolved.cloud === "object" ? resolved.cloud : void 0;
11223
- const apiKey = cloudConfig?.apiKey?.trim();
11224
- const accessToken = cloudConfig?.accessToken?.trim();
11225
- if (apiKey && accessToken) {
11226
- throw new Error(
11227
- "Cloud mode cannot use both cloud.apiKey and cloud.accessToken. Set only one credential."
11228
- );
11229
- }
11230
- let credential = "";
11231
- let authScheme = cloudConfig?.authScheme ?? "api-key";
11232
- if (accessToken) {
11233
- credential = accessToken;
11234
- authScheme = "bearer";
11235
- } else if (apiKey) {
11236
- credential = apiKey;
11237
- }
11290
+ const credential = selectCloudCredential({
11291
+ apiKey: cloudConfig?.apiKey,
11292
+ accessToken: cloudConfig?.accessToken,
11293
+ authScheme: cloudConfig?.authScheme
11294
+ });
11238
11295
  if (!credential) {
11239
11296
  throw new Error(
11240
11297
  "Cloud mode requires credentials via cloud.apiKey/cloud.accessToken or OPENSTEER_API_KEY/OPENSTEER_ACCESS_TOKEN."
11241
11298
  );
11242
11299
  }
11243
11300
  this.cloud = createCloudRuntimeState(
11244
- credential,
11301
+ credential.token,
11245
11302
  cloudConfig?.baseUrl,
11246
- authScheme
11303
+ credential.authScheme
11247
11304
  );
11248
11305
  } else {
11249
11306
  this.cloud = null;
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  Opensteer
3
- } from "../chunk-F2VDVOJO.js";
3
+ } from "../chunk-3OMXCBPD.js";
4
4
  import {
5
5
  normalizeError,
6
6
  resolveCloudSelection,
7
7
  resolveConfigWithEnv
8
- } from "../chunk-WDRMHPWL.js";
8
+ } from "../chunk-KE35RQOJ.js";
9
9
  import "../chunk-3H5RRIMZ.js";
10
10
 
11
11
  // src/cli/server.ts