opensteer 0.8.9 → 0.8.11

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
@@ -1040,6 +1040,9 @@ function isBrowserCoreError(value) {
1040
1040
  // ../browser-core/src/cdp-visual-stability.ts
1041
1041
  var DEFAULT_VISUAL_STABILITY_SETTLE_MS = 750;
1042
1042
 
1043
+ // ../browser-core/src/post-load-tracker.ts
1044
+ var DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS = 400;
1045
+
1043
1046
  // ../protocol/src/identity.ts
1044
1047
  var refPrefixes = [
1045
1048
  "session",
@@ -6229,9 +6232,23 @@ var opensteerInspectStorageInputSchema = objectSchema(
6229
6232
  title: "OpensteerInspectStorageInput"
6230
6233
  }
6231
6234
  );
6235
+ var opensteerComputerMouseButtonSchema = enumSchema(["left", "middle", "right"], {
6236
+ title: "OpensteerComputerMouseButton"
6237
+ });
6238
+ var opensteerComputerKeyModifierSchema = enumSchema(
6239
+ ["Shift", "Control", "Alt", "Meta"],
6240
+ {
6241
+ title: "OpensteerComputerKeyModifier"
6242
+ }
6243
+ );
6232
6244
  var opensteerDomClickInputSchema = objectSchema(
6233
6245
  {
6234
6246
  target: opensteerTargetInputSchema,
6247
+ button: opensteerComputerMouseButtonSchema,
6248
+ clickCount: integerSchema({ minimum: 1 }),
6249
+ modifiers: arraySchema(opensteerComputerKeyModifierSchema, {
6250
+ uniqueItems: true
6251
+ }),
6235
6252
  persistAsDescription: stringSchema(),
6236
6253
  captureNetwork: stringSchema({ minLength: 1 })
6237
6254
  },
@@ -6331,18 +6348,6 @@ var opensteerSessionCloseOutputSchema = objectSchema(
6331
6348
  required: ["closed"]
6332
6349
  }
6333
6350
  );
6334
- var opensteerComputerMouseButtonSchema = enumSchema(
6335
- ["left", "middle", "right"],
6336
- {
6337
- title: "OpensteerComputerMouseButton"
6338
- }
6339
- );
6340
- var opensteerComputerKeyModifierSchema = enumSchema(
6341
- ["Shift", "Control", "Alt", "Meta"],
6342
- {
6343
- title: "OpensteerComputerKeyModifier"
6344
- }
6345
- );
6346
6351
  var opensteerComputerAnnotationSchema = enumSchema(opensteerComputerAnnotationNames, {
6347
6352
  title: "OpensteerComputerAnnotation"
6348
6353
  });
@@ -9083,6 +9088,7 @@ var NAVIGATION_VISUAL_STABILITY_PROFILE = {
9083
9088
  scope: "visible-frames",
9084
9089
  timeoutMs: 7e3
9085
9090
  };
9091
+ var NAVIGATION_POST_LOAD_CAPTURE_WINDOW_MS = 1e3;
9086
9092
  var defaultDomActionSettleObserver = {
9087
9093
  async settle(input) {
9088
9094
  if (input.trigger !== "dom-action") {
@@ -9118,6 +9124,13 @@ var defaultNavigationSettleObserver = {
9118
9124
  return false;
9119
9125
  }
9120
9126
  try {
9127
+ await input.engine.waitForPostLoadQuiet({
9128
+ pageRef: input.pageRef,
9129
+ timeoutMs: effectiveTimeout,
9130
+ quietMs: DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS,
9131
+ captureWindowMs: Math.min(NAVIGATION_POST_LOAD_CAPTURE_WINDOW_MS, effectiveTimeout),
9132
+ signal: input.signal
9133
+ });
9121
9134
  await input.engine.waitForVisualStability({
9122
9135
  pageRef: input.pageRef,
9123
9136
  timeoutMs: effectiveTimeout,
@@ -10831,15 +10844,7 @@ var MemoryDomDescriptorStore = class {
10831
10844
  // ../runtime-core/src/action-boundary.ts
10832
10845
  var actionBoundaryDiagnosticsBySignal = /* @__PURE__ */ new WeakMap();
10833
10846
  async function captureActionBoundarySnapshot(engine, pageRef) {
10834
- const frames = await engine.listFrames({ pageRef });
10835
- const mainFrame = frames.find((frame) => frame.isMainFrame);
10836
- if (!mainFrame) {
10837
- throw new Error(`page ${pageRef} does not expose a main frame`);
10838
- }
10839
- return {
10840
- pageRef,
10841
- documentRef: mainFrame.documentRef
10842
- };
10847
+ return engine.getActionBoundarySnapshot({ pageRef });
10843
10848
  }
10844
10849
  function createActionBoundaryDiagnostics(input) {
10845
10850
  return {
@@ -15426,7 +15431,7 @@ async function clearPersistedSessionRecord(rootPath, provider) {
15426
15431
  await promises.rm(resolveLiveSessionRecordPath(rootPath, provider), { force: true });
15427
15432
  }
15428
15433
  function isPersistedCloudSessionRecord(value) {
15429
- return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "cloud" && typeof value.sessionId === "string" && value.sessionId.length > 0 && typeof value.baseUrl === "string" && value.baseUrl.length > 0 && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt);
15434
+ return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "cloud" && typeof value.sessionId === "string" && value.sessionId.length > 0 && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt);
15430
15435
  }
15431
15436
  function isPersistedLocalBrowserSessionRecord(value) {
15432
15437
  return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "local" && (value.engine === "playwright" || value.engine === "abp") && typeof value.pid === "number" && Number.isFinite(value.pid) && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt) && typeof value.userDataDir === "string" && value.userDataDir.length > 0;
@@ -23070,6 +23075,7 @@ function diffInteractionTraces(left, right) {
23070
23075
  // ../runtime-core/src/sdk/runtime.ts
23071
23076
  var requireForAuthRecipeHook = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
23072
23077
  var MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS = 5e3;
23078
+ var PERSISTED_NETWORK_FLUSH_TIMEOUT_MS = 5e3;
23073
23079
  var PENDING_OPERATION_EVENT_CAPTURE_LIMIT = 64;
23074
23080
  var PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS = 1e3;
23075
23081
  var OpensteerSessionRuntime = class {
@@ -23733,6 +23739,9 @@ var OpensteerSessionRuntime = class {
23733
23739
  const result = await this.requireDom().click({
23734
23740
  pageRef,
23735
23741
  target,
23742
+ ...input.button === void 0 ? {} : { button: input.button },
23743
+ ...input.clickCount === void 0 ? {} : { clickCount: input.clickCount },
23744
+ ...input.modifiers === void 0 ? {} : { modifiers: input.modifiers },
23736
23745
  timeout
23737
23746
  });
23738
23747
  return {
@@ -29209,6 +29218,29 @@ var OpensteerSessionRuntime = class {
29209
29218
  return snapshot.sessionStorage?.filter((entry) => entry.origin === origin).find((entry) => pageUrl === void 0 || entry.origin === new URL(pageUrl).origin)?.entries.find((entry) => entry.key === key)?.value;
29210
29219
  }
29211
29220
  async flushPersistedNetworkHistory() {
29221
+ if (this.sessionRef === void 0) {
29222
+ return;
29223
+ }
29224
+ const root = await this.ensureRoot();
29225
+ try {
29226
+ await withDetachedTimeoutSignal(PERSISTED_NETWORK_FLUSH_TIMEOUT_MS, async (signal) => {
29227
+ const browserRecords = await this.readBrowserNetworkRecords(
29228
+ {
29229
+ includeBodies: true,
29230
+ includeCurrentPageOnly: false
29231
+ },
29232
+ signal
29233
+ );
29234
+ await this.networkHistory.persist(browserRecords, root.registry.savedNetwork, {
29235
+ bodyWriteMode: "authoritative",
29236
+ redactSecretHeaders: false
29237
+ });
29238
+ });
29239
+ } catch (error) {
29240
+ if (!isIgnorableRuntimeBindingError(error)) {
29241
+ throw error;
29242
+ }
29243
+ }
29212
29244
  }
29213
29245
  toDomTargetRef(target) {
29214
29246
  if (target.kind === "description") {
@@ -29365,6 +29397,12 @@ var OpensteerSessionRuntime = class {
29365
29397
  return "live";
29366
29398
  } catch (error) {
29367
29399
  if (isIgnorableRuntimeBindingError(error)) {
29400
+ const remainingPages = await engine.listPages({ sessionRef }).catch(() => void 0);
29401
+ const replacementPageRef = remainingPages?.[0]?.pageRef;
29402
+ if (replacementPageRef !== void 0) {
29403
+ this.pageRef = replacementPageRef;
29404
+ return "live";
29405
+ }
29368
29406
  return "invalid";
29369
29407
  }
29370
29408
  throw error;
@@ -32643,11 +32681,25 @@ function queryAllCookies(dbPath) {
32643
32681
  FROM cookies`
32644
32682
  );
32645
32683
  stmt.setReadBigInts(true);
32646
- return stmt.all();
32684
+ return stmt.all().map(toRawCookieRow);
32647
32685
  } finally {
32648
32686
  database.close();
32649
32687
  }
32650
32688
  }
32689
+ function toRawCookieRow(row) {
32690
+ return {
32691
+ host_key: row.host_key,
32692
+ name: row.name,
32693
+ value: row.value,
32694
+ encrypted_value: row.encrypted_value,
32695
+ path: row.path,
32696
+ expires_utc: row.expires_utc,
32697
+ is_secure: row.is_secure,
32698
+ is_httponly: row.is_httponly,
32699
+ samesite: row.samesite,
32700
+ is_persistent: row.is_persistent
32701
+ };
32702
+ }
32651
32703
  async function resolveDecryptionKey(brandId, userDataDir) {
32652
32704
  if (process.platform === "darwin") {
32653
32705
  const password = await resolveKeychainPassword(brandId);
@@ -32998,7 +33050,11 @@ var OpensteerCloudClient = class {
32998
33050
  ...input.browser === void 0 ? {} : { browser: input.browser },
32999
33051
  ...input.context === void 0 ? {} : { context: input.context },
33000
33052
  ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile },
33001
- ...input.observability === void 0 ? {} : { observability: input.observability }
33053
+ ...input.observability === void 0 ? {} : { observability: input.observability },
33054
+ ...input.sourceType === void 0 ? {} : { sourceType: input.sourceType },
33055
+ ...input.sourceRef === void 0 ? {} : { sourceRef: input.sourceRef },
33056
+ ...input.localWorkspaceRootPath === void 0 ? {} : { localWorkspaceRootPath: input.localWorkspaceRootPath },
33057
+ ...input.locality === void 0 ? {} : { locality: input.locality }
33002
33058
  }
33003
33059
  });
33004
33060
  return await response.json();
@@ -33024,6 +33080,30 @@ var OpensteerCloudClient = class {
33024
33080
  });
33025
33081
  return await response.json();
33026
33082
  }
33083
+ async getSessionRecording(sessionId) {
33084
+ const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}/recording`, {
33085
+ method: "GET"
33086
+ });
33087
+ return await response.json();
33088
+ }
33089
+ async startSessionRecording(sessionId) {
33090
+ const response = await this.request(
33091
+ `/v1/sessions/${encodeURIComponent(sessionId)}/recording/start`,
33092
+ {
33093
+ method: "POST"
33094
+ }
33095
+ );
33096
+ return await response.json();
33097
+ }
33098
+ async stopSessionRecording(sessionId) {
33099
+ const response = await this.request(
33100
+ `/v1/sessions/${encodeURIComponent(sessionId)}/recording/stop`,
33101
+ {
33102
+ method: "POST"
33103
+ }
33104
+ );
33105
+ return await response.json();
33106
+ }
33027
33107
  async closeSession(sessionId) {
33028
33108
  const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}`, {
33029
33109
  method: "DELETE"
@@ -33214,9 +33294,11 @@ function resolveCloudConfig(input = {}) {
33214
33294
  if (!baseUrl || baseUrl.trim().length === 0) {
33215
33295
  throw new Error("provider=cloud requires OPENSTEER_BASE_URL or provider.baseUrl.");
33216
33296
  }
33297
+ const appBaseUrl = cloudProvider?.appBaseUrl ?? input.environment?.OPENSTEER_CLOUD_APP_BASE_URL;
33217
33298
  return {
33218
33299
  apiKey: apiKey.trim(),
33219
33300
  baseUrl: baseUrl.trim().replace(/\/+$/, ""),
33301
+ ...appBaseUrl === void 0 || appBaseUrl.trim().length === 0 ? {} : { appBaseUrl: appBaseUrl.trim().replace(/\/+$/, "") },
33220
33302
  ...cloudProvider?.browserProfile === void 0 ? {} : { browserProfile: cloudProvider.browserProfile }
33221
33303
  };
33222
33304
  }
@@ -33235,6 +33317,9 @@ var OpensteerSemanticRestClient = class {
33235
33317
  this.connection = connection;
33236
33318
  }
33237
33319
  async invoke(operation, input) {
33320
+ return this.invokeInternal(operation, input, false);
33321
+ }
33322
+ async invokeInternal(operation, input, hasRetried) {
33238
33323
  const endpoint = opensteerSemanticRestEndpoints.find((entry) => entry.name === operation);
33239
33324
  if (!endpoint) {
33240
33325
  throw new Error(`unsupported semantic operation ${operation}`);
@@ -33244,7 +33329,7 @@ var OpensteerSemanticRestClient = class {
33244
33329
  });
33245
33330
  let response;
33246
33331
  try {
33247
- response = await fetch(`${this.connection.baseUrl}${endpoint.path}`, {
33332
+ response = await fetch(`${await this.connection.getBaseUrl()}${endpoint.path}`, {
33248
33333
  method: "POST",
33249
33334
  headers: {
33250
33335
  authorization: await this.connection.getAuthorizationHeader(),
@@ -33266,6 +33351,9 @@ var OpensteerSemanticRestClient = class {
33266
33351
  }
33267
33352
  return envelope.data;
33268
33353
  } catch (error) {
33354
+ if (!hasRetried && this.connection.handleError && await this.connection.handleError(error, { operation })) {
33355
+ return this.invokeInternal(operation, input, true);
33356
+ }
33269
33357
  if (operation === "session.close" && isFetchFailure(error)) {
33270
33358
  return { closed: true };
33271
33359
  }
@@ -33399,7 +33487,10 @@ var OpensteerCloudAutomationClient = class {
33399
33487
  }
33400
33488
  async connect() {
33401
33489
  const grant = await this.issueGrant("automation");
33402
- const wsUrl = new URL(grant.wsUrl);
33490
+ if (grant.transport !== "ws") {
33491
+ throw new Error(`cloud issued an invalid ${grant.kind} grant transport`);
33492
+ }
33493
+ const wsUrl = new URL(grant.url);
33403
33494
  wsUrl.searchParams.set("token", grant.token);
33404
33495
  const socket = new WebSocket2__default.default(wsUrl);
33405
33496
  this.socket = socket;
@@ -33764,7 +33855,7 @@ var CloudSessionProxy = class {
33764
33855
  cloud;
33765
33856
  observability;
33766
33857
  sessionId;
33767
- sessionBaseUrl;
33858
+ semanticGrant;
33768
33859
  client;
33769
33860
  automation;
33770
33861
  workspaceStore;
@@ -33815,7 +33906,7 @@ var CloudSessionProxy = class {
33815
33906
  reconnectable: this.workspace !== void 0 || this.sessionId !== void 0 || persisted !== void 0,
33816
33907
  capabilities: {
33817
33908
  semanticOperations: opensteerSemanticOperationNames,
33818
- sessionGrants: ["automation", "view", "cdp"],
33909
+ sessionGrants: ["semantic", "automation", "view", "cdp"],
33819
33910
  instrumentation: {
33820
33911
  route: true,
33821
33912
  interceptScript: true,
@@ -34057,13 +34148,12 @@ var CloudSessionProxy = class {
34057
34148
  return this.requireClient().invoke("computer.execute", input);
34058
34149
  }
34059
34150
  async close() {
34060
- const session = await this.loadPersistedSession() ?? (this.sessionId === void 0 || this.sessionBaseUrl === void 0 ? void 0 : {
34151
+ const session = await this.loadPersistedSession() ?? (this.sessionId === void 0 ? void 0 : {
34061
34152
  layout: "opensteer-session",
34062
34153
  version: 1,
34063
34154
  provider: "cloud",
34064
34155
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
34065
34156
  sessionId: this.sessionId,
34066
- baseUrl: this.sessionBaseUrl,
34067
34157
  startedAt: Date.now(),
34068
34158
  updatedAt: Date.now()
34069
34159
  });
@@ -34082,7 +34172,7 @@ var CloudSessionProxy = class {
34082
34172
  this.automation = void 0;
34083
34173
  this.client = void 0;
34084
34174
  this.sessionId = void 0;
34085
- this.sessionBaseUrl = void 0;
34175
+ this.semanticGrant = void 0;
34086
34176
  if (this.cleanupRootOnClose) {
34087
34177
  await promises.rm(this.rootPath, { recursive: true, force: true }).catch(() => void 0);
34088
34178
  }
@@ -34098,39 +34188,56 @@ var CloudSessionProxy = class {
34098
34188
  await this.automation?.close().catch(() => void 0);
34099
34189
  this.automation = void 0;
34100
34190
  this.sessionId = void 0;
34101
- this.sessionBaseUrl = void 0;
34191
+ this.semanticGrant = void 0;
34102
34192
  }
34103
34193
  async ensureSession(input = {}) {
34104
34194
  if (this.client) {
34105
34195
  return;
34106
34196
  }
34107
34197
  assertSupportedCloudBrowserMode(input.browser);
34198
+ const localCloud = this.shouldUseLocalCloudTransport();
34199
+ const browserProfile = resolveCloudBrowserProfile(this.cloud, input);
34108
34200
  const persisted = await this.loadPersistedSession();
34109
34201
  if (persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
34110
- await this.syncRegistryToCloud();
34202
+ if (localCloud) {
34203
+ void this.syncRegistryToCloud();
34204
+ } else {
34205
+ await this.syncRegistryToCloud();
34206
+ }
34111
34207
  this.bindClient(persisted);
34112
34208
  return;
34113
34209
  }
34114
- await this.syncRegistryToCloud();
34115
- const session = await this.cloud.createSession({
34210
+ if (localCloud) {
34211
+ void this.syncRegistryToCloud();
34212
+ } else {
34213
+ await this.syncRegistryToCloud();
34214
+ }
34215
+ const baseCreateInput = {
34116
34216
  ...this.workspace === void 0 ? {} : { name: this.workspace },
34117
34217
  ...input.launch === void 0 ? {} : { browser: input.launch },
34118
34218
  ...input.context === void 0 ? {} : { context: input.context },
34119
34219
  ...this.observability === void 0 ? {} : { observability: this.observability },
34120
- ...resolveCloudBrowserProfile(this.cloud, input) === void 0 ? {} : { browserProfile: resolveCloudBrowserProfile(this.cloud, input) }
34121
- });
34220
+ ...browserProfile === void 0 ? {} : { browserProfile }
34221
+ };
34222
+ const createInput = localCloud && this.workspace !== void 0 ? {
34223
+ ...baseCreateInput,
34224
+ sourceType: "local-cloud",
34225
+ sourceRef: this.workspace,
34226
+ localWorkspaceRootPath: this.rootPath,
34227
+ locality: "auto"
34228
+ } : baseCreateInput;
34229
+ const session = await this.cloud.createSession(createInput);
34122
34230
  const record = {
34123
34231
  layout: "opensteer-session",
34124
34232
  version: 1,
34125
34233
  provider: "cloud",
34126
34234
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
34127
34235
  sessionId: session.sessionId,
34128
- baseUrl: session.baseUrl,
34129
34236
  startedAt: Date.now(),
34130
34237
  updatedAt: Date.now()
34131
34238
  };
34132
34239
  await this.writePersistedSession(record);
34133
- this.bindClient(record);
34240
+ this.bindClient(record, session.initialGrants?.semantic);
34134
34241
  }
34135
34242
  async syncRegistryToCloud() {
34136
34243
  if (this.workspace === void 0) {
@@ -34139,15 +34246,16 @@ var CloudSessionProxy = class {
34139
34246
  try {
34140
34247
  const workspaceStore = await this.ensureWorkspaceStore();
34141
34248
  await syncLocalRegistryToCloud(this.cloud, this.workspace, workspaceStore);
34142
- } catch (error) {
34249
+ } catch {
34143
34250
  }
34144
34251
  }
34145
- bindClient(record) {
34252
+ bindClient(record, initialSemanticGrant) {
34146
34253
  this.sessionId = record.sessionId;
34147
- this.sessionBaseUrl = record.baseUrl;
34254
+ this.semanticGrant = initialSemanticGrant?.kind === "semantic" ? initialSemanticGrant : void 0;
34148
34255
  this.client = new OpensteerSemanticRestClient({
34149
- baseUrl: record.baseUrl,
34150
- getAuthorizationHeader: async () => this.cloud.buildAuthorizationHeader()
34256
+ getBaseUrl: async () => (await this.ensureSemanticGrant()).url,
34257
+ getAuthorizationHeader: async () => `Bearer ${(await this.ensureSemanticGrant()).token}`,
34258
+ handleError: (error) => this.handleSemanticClientError(error)
34151
34259
  });
34152
34260
  this.automation = new OpensteerCloudAutomationClient(this.cloud, record.sessionId);
34153
34261
  }
@@ -34196,6 +34304,43 @@ var CloudSessionProxy = class {
34196
34304
  }
34197
34305
  return this.automation;
34198
34306
  }
34307
+ async ensureSemanticGrant(forceRefresh = false) {
34308
+ if (!forceRefresh && this.semanticGrant?.kind === "semantic" && this.semanticGrant.expiresAt > Date.now() + 1e4) {
34309
+ return this.semanticGrant;
34310
+ }
34311
+ if (!this.sessionId) {
34312
+ throw new Error("Cloud session has not been initialized.");
34313
+ }
34314
+ const issued = await this.cloud.issueAccess(this.sessionId, ["semantic"]);
34315
+ const grant = issued.grants.semantic;
34316
+ if (!grant || grant.transport !== "http") {
34317
+ throw new Error("cloud did not issue a valid semantic grant");
34318
+ }
34319
+ this.semanticGrant = grant;
34320
+ return grant;
34321
+ }
34322
+ async handleSemanticClientError(error) {
34323
+ if (!(error instanceof OpensteerSemanticRestError)) {
34324
+ return false;
34325
+ }
34326
+ if (error.statusCode !== 401 && error.statusCode !== 404) {
34327
+ return false;
34328
+ }
34329
+ this.semanticGrant = void 0;
34330
+ try {
34331
+ await this.ensureSemanticGrant(true);
34332
+ return true;
34333
+ } catch {
34334
+ return false;
34335
+ }
34336
+ }
34337
+ shouldUseLocalCloudTransport() {
34338
+ if (this.workspace === void 0) {
34339
+ return false;
34340
+ }
34341
+ const config = this.cloud.getConfig();
34342
+ return isLoopbackBaseUrl(config.baseUrl);
34343
+ }
34199
34344
  };
34200
34345
  function resolveCloudBrowserProfile(cloud, input) {
34201
34346
  return input.browserProfile ?? cloud.getConfig().browserProfile;
@@ -34211,6 +34356,15 @@ function assertSupportedCloudBrowserMode(browser) {
34211
34356
  function isMissingCloudSessionError(error) {
34212
34357
  return error instanceof Error && /\b404\b/.test(error.message);
34213
34358
  }
34359
+ function isLoopbackBaseUrl(baseUrl) {
34360
+ let url;
34361
+ try {
34362
+ url = new URL(baseUrl);
34363
+ } catch {
34364
+ return false;
34365
+ }
34366
+ return url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1" || url.hostname === "[::1]";
34367
+ }
34214
34368
 
34215
34369
  // src/sdk/runtime-resolution.ts
34216
34370
  function resolveOpensteerRuntimeConfig(input = {}) {
@@ -34342,7 +34496,13 @@ var Opensteer = class {
34342
34496
  return this.runtime.addInitScript(normalized);
34343
34497
  }
34344
34498
  async click(input) {
34345
- const normalized = normalizeTargetOptions(input);
34499
+ const { button, clickCount, modifiers, ...target } = input;
34500
+ const normalized = {
34501
+ ...normalizeTargetOptions(target),
34502
+ ...button === void 0 ? {} : { button },
34503
+ ...clickCount === void 0 ? {} : { clickCount },
34504
+ ...modifiers === void 0 ? {} : { modifiers }
34505
+ };
34346
34506
  return this.runtime.click(normalized);
34347
34507
  }
34348
34508
  async hover(input) {
@@ -34664,6 +34824,7 @@ exports.cloneElementPath = cloneElementPath;
34664
34824
  exports.cloneReplayElementPath = cloneReplayElementPath;
34665
34825
  exports.cloneStructuralElementAnchor = cloneStructuralElementAnchor;
34666
34826
  exports.createArtifactStore = createArtifactStore;
34827
+ exports.createDomDescriptorStore = createDomDescriptorStore;
34667
34828
  exports.createDomRuntime = createDomRuntime;
34668
34829
  exports.createFilesystemOpensteerWorkspace = createFilesystemOpensteerWorkspace;
34669
34830
  exports.createObservationStore = createObservationStore;