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/index.cjs CHANGED
@@ -1301,6 +1301,65 @@ function toJsonSafeValue(value, seen) {
1301
1301
  return void 0;
1302
1302
  }
1303
1303
 
1304
+ // src/cloud/credential-selection.ts
1305
+ function selectCloudCredential(options) {
1306
+ const apiKey = normalizeNonEmptyString(options.apiKey);
1307
+ const accessToken = normalizeNonEmptyString(options.accessToken);
1308
+ if (apiKey) {
1309
+ if (options.authScheme === "bearer") {
1310
+ return {
1311
+ apiKey,
1312
+ authScheme: "bearer",
1313
+ kind: "access-token",
1314
+ token: apiKey,
1315
+ compatibilityBearerApiKey: true
1316
+ };
1317
+ }
1318
+ return {
1319
+ apiKey,
1320
+ authScheme: "api-key",
1321
+ kind: "api-key",
1322
+ token: apiKey
1323
+ };
1324
+ }
1325
+ if (accessToken) {
1326
+ return {
1327
+ accessToken,
1328
+ authScheme: "bearer",
1329
+ kind: "access-token",
1330
+ token: accessToken
1331
+ };
1332
+ }
1333
+ return null;
1334
+ }
1335
+ function selectCloudCredentialByPrecedence(layers, authScheme) {
1336
+ for (const layer of layers) {
1337
+ const hasApiKey = layer.hasApiKey ?? Object.prototype.hasOwnProperty.call(layer, "apiKey");
1338
+ const hasAccessToken = layer.hasAccessToken ?? Object.prototype.hasOwnProperty.call(layer, "accessToken");
1339
+ if (!hasApiKey && !hasAccessToken) {
1340
+ continue;
1341
+ }
1342
+ return {
1343
+ source: layer.source,
1344
+ apiKey: layer.apiKey,
1345
+ accessToken: layer.accessToken,
1346
+ hasApiKey,
1347
+ hasAccessToken,
1348
+ credential: selectCloudCredential({
1349
+ apiKey: layer.apiKey,
1350
+ accessToken: layer.accessToken,
1351
+ authScheme: layer.authScheme ?? authScheme
1352
+ })
1353
+ };
1354
+ }
1355
+ return null;
1356
+ }
1357
+ function normalizeNonEmptyString(value) {
1358
+ if (typeof value !== "string") return void 0;
1359
+ const normalized = value.trim();
1360
+ return normalized.length ? normalized : void 0;
1361
+ }
1362
+
1304
1363
  // src/storage/namespace.ts
1305
1364
  var import_path2 = __toESM(require("path"), 1);
1306
1365
  var DEFAULT_NAMESPACE = "default";
@@ -1625,11 +1684,6 @@ function normalizeCloudOptions(value) {
1625
1684
  }
1626
1685
  return value;
1627
1686
  }
1628
- function normalizeNonEmptyString(value) {
1629
- if (typeof value !== "string") return void 0;
1630
- const normalized = value.trim();
1631
- return normalized.length ? normalized : void 0;
1632
- }
1633
1687
  function parseCloudEnabled(value, source) {
1634
1688
  if (value == null) return void 0;
1635
1689
  if (typeof value === "boolean") return value;
@@ -1638,6 +1692,18 @@ function parseCloudEnabled(value, source) {
1638
1692
  `Invalid ${source} value "${String(value)}". Use true, false, or a cloud options object.`
1639
1693
  );
1640
1694
  }
1695
+ function resolveCloudCredentialFields(selectedLayer) {
1696
+ const credential = selectedLayer?.credential;
1697
+ if (!credential) return {};
1698
+ if (credential.kind === "api-key" || credential.compatibilityBearerApiKey === true && selectedLayer?.source !== "env") {
1699
+ return {
1700
+ apiKey: credential.token
1701
+ };
1702
+ }
1703
+ return {
1704
+ accessToken: credential.token
1705
+ };
1706
+ }
1641
1707
  function resolveCloudSelection(config, env = process.env) {
1642
1708
  const configCloud = parseCloudEnabled(config.cloud, "cloud");
1643
1709
  if (configCloud !== void 0) {
@@ -1674,6 +1740,9 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1674
1740
  });
1675
1741
  assertNoLegacyAiConfig(".opensteer/config.json", fileConfig);
1676
1742
  assertNoLegacyRuntimeConfig(".opensteer/config.json", fileConfig);
1743
+ const fileCloudOptions = normalizeCloudOptions(fileConfig.cloud);
1744
+ const fileHasCloudApiKey = hasOwn(fileCloudOptions, "apiKey");
1745
+ const fileHasCloudAccessToken = hasOwn(fileCloudOptions, "accessToken");
1677
1746
  const fileRootDir = typeof fileConfig.storage?.rootDir === "string" ? fileConfig.storage.rootDir : void 0;
1678
1747
  const envRootDir = input.storage?.rootDir ?? fileRootDir ?? initialRootDir;
1679
1748
  const env = resolveEnv(envRootDir, {
@@ -1712,13 +1781,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1712
1781
  const envAccessTokenRaw = resolveOpensteerAccessToken(env);
1713
1782
  const envBaseUrl = resolveOpensteerBaseUrl(env);
1714
1783
  const envAuthScheme = resolveOpensteerAuthScheme(env);
1715
- if (envApiKey && envAccessTokenRaw) {
1716
- throw new Error(
1717
- "OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
1718
- );
1719
- }
1720
- const envAccessToken = envAccessTokenRaw || (envAuthScheme === "bearer" ? envApiKey : void 0);
1721
- const envApiCredential = envAuthScheme === "bearer" && !envAccessTokenRaw ? void 0 : envApiKey;
1722
1784
  const envCloudProfileId = resolveOpensteerCloudProfileId(env);
1723
1785
  const envCloudProfileReuseIfActive = resolveOpensteerCloudProfileReuseIfActive(env);
1724
1786
  const envCloudAnnounce = parseCloudAnnounce(
@@ -1747,11 +1809,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1747
1809
  const inputHasCloudBaseUrl = Boolean(
1748
1810
  inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
1749
1811
  );
1750
- if (normalizeNonEmptyString(inputCloudOptions?.apiKey) && normalizeNonEmptyString(inputCloudOptions?.accessToken)) {
1751
- throw new Error(
1752
- "cloud.apiKey and cloud.accessToken are mutually exclusive. Set only one."
1753
- );
1754
- }
1755
1812
  const cloudSelection = resolveCloudSelection({
1756
1813
  cloud: resolved.cloud
1757
1814
  }, env);
@@ -1762,11 +1819,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1762
1819
  accessToken: resolvedCloudAccessTokenRaw,
1763
1820
  ...resolvedCloudRest
1764
1821
  } = resolvedCloud;
1765
- if (normalizeNonEmptyString(resolvedCloudApiKeyRaw) && normalizeNonEmptyString(resolvedCloudAccessTokenRaw)) {
1766
- throw new Error(
1767
- "Cloud config cannot include both apiKey and accessToken at the same time."
1768
- );
1769
- }
1770
1822
  const resolvedCloudBrowserProfile = normalizeCloudBrowserProfileOptions(
1771
1823
  resolvedCloud.browserProfile,
1772
1824
  "resolved.cloud.browserProfile"
@@ -1778,25 +1830,40 @@ function resolveConfigWithEnv(input = {}, options = {}) {
1778
1830
  const browserProfile = inputCloudBrowserProfile ?? envCloudBrowserProfile ?? resolvedCloudBrowserProfile;
1779
1831
  let authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedCloud.authScheme, "cloud.authScheme") ?? "api-key";
1780
1832
  const announce = inputCloudAnnounce ?? envCloudAnnounce ?? parseCloudAnnounce(resolvedCloud.announce, "cloud.announce") ?? "always";
1781
- const credentialOverriddenByInput = inputHasCloudApiKey || inputHasCloudAccessToken;
1782
- let apiKey = normalizeNonEmptyString(resolvedCloudApiKeyRaw);
1783
- let accessToken = normalizeNonEmptyString(resolvedCloudAccessTokenRaw);
1784
- if (!credentialOverriddenByInput) {
1785
- if (envAccessToken) {
1786
- accessToken = envAccessToken;
1787
- apiKey = void 0;
1788
- } else if (envApiCredential) {
1789
- apiKey = envApiCredential;
1790
- accessToken = void 0;
1791
- }
1792
- }
1833
+ const selectedCredentialLayer = selectCloudCredentialByPrecedence(
1834
+ [
1835
+ {
1836
+ source: "input",
1837
+ apiKey: inputCloudOptions?.apiKey,
1838
+ accessToken: inputCloudOptions?.accessToken,
1839
+ hasApiKey: inputHasCloudApiKey,
1840
+ hasAccessToken: inputHasCloudAccessToken
1841
+ },
1842
+ {
1843
+ source: "env",
1844
+ apiKey: envApiKey,
1845
+ accessToken: envAccessTokenRaw,
1846
+ hasApiKey: envApiKey !== void 0,
1847
+ hasAccessToken: envAccessTokenRaw !== void 0
1848
+ },
1849
+ {
1850
+ source: "file",
1851
+ apiKey: fileCloudOptions?.apiKey,
1852
+ accessToken: fileCloudOptions?.accessToken,
1853
+ hasApiKey: fileHasCloudApiKey,
1854
+ hasAccessToken: fileHasCloudAccessToken
1855
+ }
1856
+ ],
1857
+ authScheme
1858
+ );
1859
+ const { apiKey, accessToken } = resolveCloudCredentialFields(selectedCredentialLayer);
1793
1860
  if (accessToken) {
1794
1861
  authScheme = "bearer";
1795
1862
  }
1796
1863
  resolved.cloud = {
1797
1864
  ...resolvedCloudRest,
1798
- ...inputHasCloudApiKey ? { apiKey: resolvedCloudApiKeyRaw } : apiKey ? { apiKey } : {},
1799
- ...inputHasCloudAccessToken ? { accessToken: resolvedCloudAccessTokenRaw } : accessToken ? { accessToken } : {},
1865
+ ...apiKey ? { apiKey } : selectedCredentialLayer?.hasApiKey && !accessToken ? { apiKey: selectedCredentialLayer.apiKey } : {},
1866
+ ...accessToken ? { accessToken } : selectedCredentialLayer?.hasAccessToken && !apiKey ? { accessToken: selectedCredentialLayer.accessToken } : {},
1800
1867
  authScheme,
1801
1868
  announce,
1802
1869
  ...browserProfile ? { browserProfile } : {}
@@ -11321,30 +11388,20 @@ var Opensteer = class _Opensteer {
11321
11388
  this.pool = new BrowserPool(resolved.browser || {});
11322
11389
  if (cloudSelection.cloud) {
11323
11390
  const cloudConfig = resolved.cloud && typeof resolved.cloud === "object" ? resolved.cloud : void 0;
11324
- const apiKey = cloudConfig?.apiKey?.trim();
11325
- const accessToken = cloudConfig?.accessToken?.trim();
11326
- if (apiKey && accessToken) {
11327
- throw new Error(
11328
- "Cloud mode cannot use both cloud.apiKey and cloud.accessToken. Set only one credential."
11329
- );
11330
- }
11331
- let credential = "";
11332
- let authScheme = cloudConfig?.authScheme ?? "api-key";
11333
- if (accessToken) {
11334
- credential = accessToken;
11335
- authScheme = "bearer";
11336
- } else if (apiKey) {
11337
- credential = apiKey;
11338
- }
11391
+ const credential = selectCloudCredential({
11392
+ apiKey: cloudConfig?.apiKey,
11393
+ accessToken: cloudConfig?.accessToken,
11394
+ authScheme: cloudConfig?.authScheme
11395
+ });
11339
11396
  if (!credential) {
11340
11397
  throw new Error(
11341
11398
  "Cloud mode requires credentials via cloud.apiKey/cloud.accessToken or OPENSTEER_API_KEY/OPENSTEER_ACCESS_TOKEN."
11342
11399
  );
11343
11400
  }
11344
11401
  this.cloud = createCloudRuntimeState(
11345
- credential,
11402
+ credential.token,
11346
11403
  cloudConfig?.baseUrl,
11347
- authScheme
11404
+ credential.authScheme
11348
11405
  );
11349
11406
  } else {
11350
11407
  this.cloud = null;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BrowserProfileClient
3
- } from "./chunk-WJI7TGBQ.js";
3
+ } from "./chunk-FTKWQ6X3.js";
4
4
  import {
5
5
  ActionWsClient,
6
6
  CounterResolutionError,
@@ -78,7 +78,7 @@ import {
78
78
  switchTab,
79
79
  typeText,
80
80
  waitForVisualStability
81
- } from "./chunk-F2VDVOJO.js";
81
+ } from "./chunk-3OMXCBPD.js";
82
82
  import {
83
83
  CloudCdpClient,
84
84
  CloudSessionClient,
@@ -87,7 +87,7 @@ import {
87
87
  cloudUnsupportedMethodError,
88
88
  normalizeNamespace,
89
89
  resolveNamespaceDir
90
- } from "./chunk-WDRMHPWL.js";
90
+ } from "./chunk-KE35RQOJ.js";
91
91
  import {
92
92
  createResolveCallback
93
93
  } from "./chunk-DN3GI5CH.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opensteer",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Open-source browser automation SDK and CLI that lets AI agents build complex scrapers directly in your codebase.",
5
5
  "license": "MIT",
6
6
  "type": "module",