opensteer 0.9.5 → 0.9.6

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
@@ -1037,9 +1037,6 @@ function isBrowserCoreError(value) {
1037
1037
  return value instanceof BrowserCoreError;
1038
1038
  }
1039
1039
 
1040
- // ../browser-core/src/cdp-visual-stability.ts
1041
- var DEFAULT_VISUAL_STABILITY_SETTLE_MS = 750;
1042
-
1043
1040
  // ../browser-core/src/post-load-tracker.ts
1044
1041
  var DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS = 400;
1045
1042
 
@@ -6845,21 +6842,6 @@ var DEFAULT_SETTLE_DELAYS = {
6845
6842
  "dom-action": 100,
6846
6843
  snapshot: 0
6847
6844
  };
6848
- var defaultSnapshotSettleObserver = {
6849
- async settle(input) {
6850
- if (input.trigger !== "snapshot") {
6851
- return false;
6852
- }
6853
- await input.engine.waitForVisualStability({
6854
- pageRef: input.pageRef,
6855
- ...input.remainingMs === void 0 ? {} : { timeoutMs: input.remainingMs },
6856
- settleMs: DEFAULT_VISUAL_STABILITY_SETTLE_MS,
6857
- scope: "visible-frames"
6858
- });
6859
- return true;
6860
- }
6861
- };
6862
- Object.freeze(defaultSnapshotSettleObserver);
6863
6845
  var DOM_ACTION_VISUAL_STABILITY_PROFILES = {
6864
6846
  "dom.click": { settleMs: 750, scope: "visible-frames", timeoutMs: 7e3 },
6865
6847
  "dom.input": { settleMs: 750, scope: "visible-frames", timeoutMs: 7e3 },
@@ -6938,7 +6920,6 @@ var defaultNavigationSettleObserver = {
6938
6920
  };
6939
6921
  Object.freeze(defaultNavigationSettleObserver);
6940
6922
  var DEFAULT_SETTLE_OBSERVERS = Object.freeze([
6941
- defaultSnapshotSettleObserver,
6942
6923
  defaultDomActionSettleObserver,
6943
6924
  defaultNavigationSettleObserver
6944
6925
  ]);
@@ -7391,6 +7372,9 @@ function buildClauseSelector(node, clause) {
7391
7372
  if (!clause || typeof clause !== "object") {
7392
7373
  return "";
7393
7374
  }
7375
+ if (clause.kind === "text") {
7376
+ return "";
7377
+ }
7394
7378
  if (clause.kind === "position") {
7395
7379
  if (clause.axis === "nthOfType") {
7396
7380
  return `:nth-of-type(${Math.max(1, Number(node.position?.nthOfType || 1))})`;
@@ -7515,7 +7499,7 @@ function resolveExtractedValueInContext(normalizedValue, options) {
7515
7499
  function stripPositionClauses(nodes) {
7516
7500
  return (nodes || []).map((node) => ({
7517
7501
  ...node,
7518
- match: (node.match || []).filter((clause) => clause.kind !== "position")
7502
+ match: (node.match || []).filter((clause) => clause.kind !== "position" && clause.kind !== "text")
7519
7503
  }));
7520
7504
  }
7521
7505
  function dedupeSelectors(selectors) {
@@ -8092,9 +8076,17 @@ function resolveDomPathInScope(index, domPath, scope) {
8092
8076
  if (!candidates.length) {
8093
8077
  return null;
8094
8078
  }
8079
+ const lastNode = domPath[domPath.length - 1];
8080
+ const textClauses = lastNode?.match.filter((c) => c.kind === "text") ?? [];
8095
8081
  let fallback = null;
8096
8082
  for (const selector of candidates) {
8097
- const matches = querySelectorAllInScope(index, selector, scope);
8083
+ let matches = querySelectorAllInScope(index, selector, scope);
8084
+ if (textClauses.length > 0 && matches.length > 1) {
8085
+ const filtered = matches.filter((node) => matchesTextClauses(node, textClauses));
8086
+ if (filtered.length > 0) {
8087
+ matches = filtered;
8088
+ }
8089
+ }
8098
8090
  if (matches.length === 1) {
8099
8091
  return {
8100
8092
  node: matches[0],
@@ -8114,6 +8106,10 @@ function resolveDomPathInScope(index, domPath, scope) {
8114
8106
  }
8115
8107
  return fallback;
8116
8108
  }
8109
+ function matchesTextClauses(node, clauses) {
8110
+ const text = (node.textContent ?? "").replace(/\s+/g, " ").trim();
8111
+ return clauses.every((clause) => text.includes(clause.value));
8112
+ }
8117
8113
  function queryAllDomPathInScope(index, domPath, scope) {
8118
8114
  const selectors = buildPathCandidates(domPath);
8119
8115
  for (const selector of selectors) {
@@ -8272,7 +8268,13 @@ function clonePathNode(node) {
8272
8268
  };
8273
8269
  }
8274
8270
  function cloneMatchClause(clause) {
8275
- return clause.kind === "position" ? { kind: "position", axis: clause.axis } : {
8271
+ if (clause.kind === "position") {
8272
+ return { kind: "position", axis: clause.axis };
8273
+ }
8274
+ if (clause.kind === "text") {
8275
+ return { kind: "text", value: clause.value };
8276
+ }
8277
+ return {
8276
8278
  kind: "attr",
8277
8279
  key: clause.key,
8278
8280
  ...clause.op === void 0 ? {} : { op: clause.op },
@@ -8327,6 +8329,13 @@ function normalizeMatch(rawMatch, attrs, position, tag) {
8327
8329
  op,
8328
8330
  ...value === void 0 ? {} : { value }
8329
8331
  });
8332
+ continue;
8333
+ }
8334
+ if (record.kind === "text") {
8335
+ const textValue = typeof record.value === "string" ? record.value.trim() : "";
8336
+ if (textValue) {
8337
+ push({ kind: "text", value: textValue.slice(0, 80) });
8338
+ }
8330
8339
  }
8331
8340
  }
8332
8341
  }
@@ -8694,7 +8703,7 @@ function isTimeoutError(error) {
8694
8703
  }
8695
8704
 
8696
8705
  // ../runtime-core/src/runtimes/dom/executor.ts
8697
- var MAX_DOM_ACTION_ATTEMPTS = 3;
8706
+ var MAX_DOM_ACTION_ATTEMPTS = 2;
8698
8707
  var DEFAULT_SCROLL_OPTIONS = {
8699
8708
  block: "center",
8700
8709
  inline: "center"
@@ -9181,11 +9190,12 @@ var DomActionExecutor = class {
9181
9190
  throw this.createActionabilityError(
9182
9191
  operation,
9183
9192
  "obscured",
9184
- `hit test resolved ${hit.nodeRef} outside the target subtree rooted at ${resolved.nodeRef}`,
9193
+ `target is obscured by ${assessment.blockingDescription ?? "another element"} at the click point`,
9185
9194
  {
9186
9195
  ...details,
9187
9196
  hitRelation: assessment.relation,
9188
9197
  ...assessment.ambiguous === void 0 ? {} : { hitAmbiguous: assessment.ambiguous },
9198
+ ...assessment.blockingDescription === void 0 ? {} : { blockingDescription: assessment.blockingDescription },
9189
9199
  ...assessment.canonicalTarget === void 0 ? {} : {
9190
9200
  canonicalNodeRef: assessment.canonicalTarget.nodeRef,
9191
9201
  canonicalDocumentRef: assessment.canonicalTarget.documentRef,
@@ -9199,8 +9209,7 @@ var DomActionExecutor = class {
9199
9209
  hitMissingFromSnapshot: !resolved.snapshot.nodes.some(
9200
9210
  (node) => node.nodeRef === hit.nodeRef
9201
9211
  )
9202
- },
9203
- true
9212
+ }
9204
9213
  );
9205
9214
  }
9206
9215
  async resolveActionablePointerTarget(session, operation, resolved) {
@@ -9412,7 +9421,12 @@ var DefaultDomRuntime = class {
9412
9421
  });
9413
9422
  }
9414
9423
  async buildPath(input) {
9415
- return sanitizeReplayElementPath(await this.requireBridge().buildReplayPath(input.locator));
9424
+ return sanitizeReplayElementPath(
9425
+ await this.requireBridge().buildReplayPath(
9426
+ input.locator,
9427
+ input.enableTextMatch ? { enableTextMatch: true } : void 0
9428
+ )
9429
+ );
9416
9430
  }
9417
9431
  async resolveTarget(input) {
9418
9432
  return this.withSnapshotSession((session) => this.resolveTargetWithSession(session, input));
@@ -9632,7 +9646,7 @@ var DefaultDomRuntime = class {
9632
9646
  if (resolvedByLocator) {
9633
9647
  const { snapshot, node } = resolvedByLocator;
9634
9648
  const anchor = await this.buildAnchorFromSnapshotNode(session, snapshot, node);
9635
- const replayPath = await this.tryBuildPathFromNode(snapshot, node);
9649
+ const replayPath = await this.tryBuildPathFromNode(snapshot, node, { enableTextMatch: true });
9636
9650
  return this.createResolvedTarget("live", snapshot, node, anchor, {
9637
9651
  ...target.persist === void 0 ? {} : { persist: target.persist },
9638
9652
  ...replayPath === void 0 ? {} : { replayPath }
@@ -9650,11 +9664,12 @@ var DefaultDomRuntime = class {
9650
9664
  const { snapshot, node } = resolved;
9651
9665
  const anchor = await this.buildAnchorFromSnapshotNode(session, snapshot, node);
9652
9666
  const writeDescriptor = descriptorWriter ?? ((input) => this.descriptors.write(input));
9653
- const replayPath = await this.tryBuildPathFromNode(snapshot, node);
9667
+ const enableTextMatch = method !== "extract";
9668
+ const replayPath = await this.tryBuildPathFromNode(snapshot, node, { enableTextMatch });
9654
9669
  const descriptor = target.persist === void 0 ? void 0 : await writeDescriptor({
9655
9670
  method,
9656
9671
  persist: target.persist,
9657
- path: replayPath ?? await this.buildPathForNode(snapshot, node),
9672
+ path: replayPath ?? await this.buildPathForNode(snapshot, node, { enableTextMatch }),
9658
9673
  sourceUrl: snapshot.url
9659
9674
  });
9660
9675
  return this.createResolvedTarget("selector", snapshot, node, anchor, {
@@ -9754,7 +9769,7 @@ var DefaultDomRuntime = class {
9754
9769
  `Unable to resolve structural anchor "${buildPathSelectorHint(anchor)}" in the current session`
9755
9770
  );
9756
9771
  }
9757
- const replayPath = await this.tryBuildPathFromNode(context.snapshot, target.node);
9772
+ const replayPath = await this.tryBuildPathFromNode(context.snapshot, target.node, { enableTextMatch: true });
9758
9773
  return this.createResolvedTarget(source, context.snapshot, target.node, anchor, {
9759
9774
  ...persist === void 0 ? {} : { persist },
9760
9775
  ...replayPath === void 0 ? {} : { replayPath }
@@ -9925,19 +9940,20 @@ var DefaultDomRuntime = class {
9925
9940
  }
9926
9941
  return this.bridge;
9927
9942
  }
9928
- async buildPathForNode(snapshot, node) {
9943
+ async buildPathForNode(snapshot, node, options) {
9929
9944
  if (node.nodeRef === void 0) {
9930
9945
  throw new Error(
9931
9946
  `snapshot node ${String(node.snapshotNodeId)} does not expose a live node reference`
9932
9947
  );
9933
9948
  }
9934
9949
  return this.buildPath({
9935
- locator: createNodeLocator(snapshot.documentRef, snapshot.documentEpoch, node.nodeRef)
9950
+ locator: createNodeLocator(snapshot.documentRef, snapshot.documentEpoch, node.nodeRef),
9951
+ ...options?.enableTextMatch ? { enableTextMatch: true } : {}
9936
9952
  });
9937
9953
  }
9938
- async tryBuildPathFromNode(snapshot, node) {
9954
+ async tryBuildPathFromNode(snapshot, node, options) {
9939
9955
  try {
9940
- return await this.buildPathForNode(snapshot, node);
9956
+ return await this.buildPathForNode(snapshot, node, options);
9941
9957
  } catch {
9942
9958
  return void 0;
9943
9959
  }
@@ -10551,6 +10567,9 @@ function relaxPathForSingleSample(path18, mode) {
10551
10567
  }
10552
10568
  return !isLast;
10553
10569
  }
10570
+ if (clause.kind === "text") {
10571
+ return false;
10572
+ }
10554
10573
  const key = String(clause.key || "").trim().toLowerCase();
10555
10574
  if (!key || !shouldKeepAttrForSingleSample(key)) {
10556
10575
  return false;
@@ -10653,9 +10672,11 @@ function buildNodeStructure(node) {
10653
10672
  }
10654
10673
  structuralAttrs[key] = value;
10655
10674
  }
10656
- const matchClauses = (node.match || []).map(
10657
- (clause) => clause.kind === "position" ? `position:${clause.axis}` : `attr:${String(clause.key || "").trim().toLowerCase()}`
10658
- ).sort();
10675
+ const matchClauses = (node.match || []).map((clause) => {
10676
+ if (clause.kind === "position") return `position:${clause.axis}`;
10677
+ if (clause.kind === "text") return `text:${clause.value}`;
10678
+ return `attr:${String(clause.key || "").trim().toLowerCase()}`;
10679
+ }).sort();
10659
10680
  return {
10660
10681
  tag,
10661
10682
  attrs: structuralAttrs,
@@ -11061,6 +11082,9 @@ function mergeMatchByMajority(matchLists, attrs, threshold, positionFlags = {
11061
11082
  });
11062
11083
  continue;
11063
11084
  }
11085
+ if (clause.kind === "text") {
11086
+ continue;
11087
+ }
11064
11088
  if (clause.axis === "nthOfType") {
11065
11089
  if (positionFlags.hasNthOfType) {
11066
11090
  merged.push({ kind: "position", axis: "nthOfType" });
@@ -13875,7 +13899,8 @@ function normalizeOpensteerEngineName(value, source = "engine") {
13875
13899
  if (normalized === "playwright" || normalized === "abp") {
13876
13900
  return normalized;
13877
13901
  }
13878
- throw new Error(
13902
+ throw new OpensteerProtocolError(
13903
+ "invalid-argument",
13879
13904
  `${source} must be one of ${OPENSTEER_ENGINE_NAMES.join(", ")}; received "${value}".`
13880
13905
  );
13881
13906
  }
@@ -13884,7 +13909,8 @@ function assertSupportedEngineOptions(input) {
13884
13909
  return;
13885
13910
  }
13886
13911
  if (typeof input.browser === "object" && input.browser !== null && input.browser.mode === "attach") {
13887
- throw new Error(
13912
+ throw new OpensteerProtocolError(
13913
+ "invalid-argument",
13888
13914
  'ABP engine does not support browser.mode="attach". Use the Playwright engine for attach flows.'
13889
13915
  );
13890
13916
  }
@@ -13892,7 +13918,8 @@ function assertSupportedEngineOptions(input) {
13892
13918
  if (unsupportedContextOptionNames.length === 0) {
13893
13919
  return;
13894
13920
  }
13895
- throw new Error(
13921
+ throw new OpensteerProtocolError(
13922
+ "invalid-argument",
13896
13923
  `ABP engine does not support ${unsupportedContextOptionNames.join(", ")}. Supported ABP context options: context.viewport.`
13897
13924
  );
13898
13925
  }
@@ -14994,6 +15021,48 @@ function isOpensteerEnvironmentKey(key) {
14994
15021
  return key.startsWith(OPENSTEER_ENV_PREFIX);
14995
15022
  }
14996
15023
 
15024
+ // src/internal/errors.ts
15025
+ function normalizeThrownOpensteerError(error, fallbackMessage) {
15026
+ if (isOpensteerProtocolError(error)) {
15027
+ return toOpensteerError(error);
15028
+ }
15029
+ if (isBrowserCoreError(error)) {
15030
+ return createOpensteerError(error.code, error.message, {
15031
+ retriable: error.retriable,
15032
+ ...error.details === void 0 ? {} : { details: error.details }
15033
+ });
15034
+ }
15035
+ if (error instanceof OpensteerAttachAmbiguousError) {
15036
+ return createOpensteerError("conflict", error.message, {
15037
+ details: {
15038
+ candidates: error.candidates,
15039
+ code: error.code,
15040
+ name: error.name
15041
+ }
15042
+ });
15043
+ }
15044
+ if (error instanceof Error && "opensteerError" in error && typeof error.opensteerError === "object" && error.opensteerError !== null) {
15045
+ const oe = error.opensteerError;
15046
+ return createOpensteerError(oe.code, oe.message, {
15047
+ retriable: oe.retriable,
15048
+ ...oe.capability === void 0 ? {} : { capability: oe.capability },
15049
+ ...oe.details === void 0 ? {} : { details: oe.details }
15050
+ });
15051
+ }
15052
+ if (error instanceof Error) {
15053
+ return createOpensteerError("operation-failed", error.message, {
15054
+ details: {
15055
+ name: error.name
15056
+ }
15057
+ });
15058
+ }
15059
+ return createOpensteerError("internal", fallbackMessage, {
15060
+ details: {
15061
+ value: error
15062
+ }
15063
+ });
15064
+ }
15065
+
14997
15066
  // src/provider/config.ts
14998
15067
  var OPENSTEER_PROVIDER_MODES = ["local", "cloud"];
14999
15068
  function assertProviderSupportsEngine(provider, engine) {
@@ -15001,7 +15070,8 @@ function assertProviderSupportsEngine(provider, engine) {
15001
15070
  return;
15002
15071
  }
15003
15072
  if (provider === "cloud") {
15004
- throw new Error(
15073
+ throw new OpensteerProtocolError(
15074
+ "invalid-argument",
15005
15075
  "ABP is not supported for provider=cloud. Cloud provider currently requires Playwright."
15006
15076
  );
15007
15077
  }
@@ -15011,7 +15081,8 @@ function normalizeOpensteerProviderMode(value, source = "OPENSTEER_PROVIDER") {
15011
15081
  if (normalized === OPENSTEER_PROVIDER_MODES[0] || normalized === OPENSTEER_PROVIDER_MODES[1]) {
15012
15082
  return normalized;
15013
15083
  }
15014
- throw new Error(
15084
+ throw new OpensteerProtocolError(
15085
+ "invalid-argument",
15015
15086
  `${source} must be one of ${OPENSTEER_PROVIDER_MODES.join(", ")}; received "${value}".`
15016
15087
  );
15017
15088
  }
@@ -15451,6 +15522,24 @@ async function sleep3(ms) {
15451
15522
  // src/cloud/client.ts
15452
15523
  var CLOUD_CLOSE_TIMEOUT_MS = 6e4;
15453
15524
  var CLOUD_CLOSE_POLL_INTERVAL_MS = 250;
15525
+ var OpensteerCloudRequestError = class extends Error {
15526
+ statusCode;
15527
+ code;
15528
+ details;
15529
+ method;
15530
+ pathname;
15531
+ url;
15532
+ constructor(args) {
15533
+ super(args.message);
15534
+ this.name = "OpensteerCloudRequestError";
15535
+ this.statusCode = args.statusCode;
15536
+ this.code = args.code;
15537
+ this.details = args.details;
15538
+ this.method = args.method;
15539
+ this.pathname = args.pathname;
15540
+ this.url = args.url;
15541
+ }
15542
+ };
15454
15543
  var OpensteerCloudClient = class {
15455
15544
  constructor(config) {
15456
15545
  this.config = config;
@@ -15626,7 +15715,11 @@ var OpensteerCloudClient = class {
15626
15715
  });
15627
15716
  }
15628
15717
  if (!response.ok) {
15629
- throw new Error(`${init.method} ${pathname} failed with ${String(response.status)}.`);
15718
+ throw await createCloudRequestError(response, {
15719
+ method: init.method,
15720
+ pathname,
15721
+ url
15722
+ });
15630
15723
  }
15631
15724
  return response;
15632
15725
  }
@@ -15674,6 +15767,36 @@ function wrapCloudFetchError(error, input) {
15674
15767
  wrapped.name = error.name;
15675
15768
  return wrapped;
15676
15769
  }
15770
+ async function createCloudRequestError(response, input) {
15771
+ const payload = await readCloudErrorPayload(response);
15772
+ return new OpensteerCloudRequestError({
15773
+ statusCode: response.status,
15774
+ method: input.method,
15775
+ pathname: input.pathname,
15776
+ url: input.url,
15777
+ message: payload?.error ?? `${input.method} ${input.pathname} failed with ${String(response.status)}.`,
15778
+ ...payload?.code === void 0 ? {} : { code: payload.code },
15779
+ ...payload?.details === void 0 ? {} : { details: payload.details }
15780
+ });
15781
+ }
15782
+ async function readCloudErrorPayload(response) {
15783
+ try {
15784
+ return asCloudErrorPayload(await response.json());
15785
+ } catch {
15786
+ return void 0;
15787
+ }
15788
+ }
15789
+ function asCloudErrorPayload(value) {
15790
+ if (value === null || typeof value !== "object") {
15791
+ return void 0;
15792
+ }
15793
+ const payload = value;
15794
+ return {
15795
+ ...typeof payload.error === "string" ? { error: payload.error } : {},
15796
+ ...typeof payload.code === "string" ? { code: payload.code } : {},
15797
+ ..."details" in payload ? { details: payload.details } : {}
15798
+ };
15799
+ }
15677
15800
 
15678
15801
  // src/cloud/config.ts
15679
15802
  function resolveCloudConfig(input = {}) {
@@ -15704,13 +15827,13 @@ function resolveCloudConfig(input = {}) {
15704
15827
 
15705
15828
  // ../runtime-core/package.json
15706
15829
  var package_default = {
15707
- version: "0.2.4"};
15830
+ version: "0.2.5"};
15708
15831
 
15709
15832
  // ../runtime-core/src/version.ts
15710
15833
  var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
15711
15834
 
15712
15835
  // ../runtime-core/src/internal/errors.ts
15713
- function normalizeThrownOpensteerError(error, fallbackMessage) {
15836
+ function normalizeThrownOpensteerError2(error, fallbackMessage) {
15714
15837
  if (isOpensteerProtocolError(error)) {
15715
15838
  return toOpensteerError(error);
15716
15839
  }
@@ -24843,7 +24966,7 @@ function toOpensteerResolvedTarget2(target) {
24843
24966
  };
24844
24967
  }
24845
24968
  function normalizeOpensteerError(error) {
24846
- return normalizeThrownOpensteerError(error, "Unknown Opensteer runtime failure");
24969
+ return normalizeThrownOpensteerError2(error, "Unknown Opensteer runtime failure");
24847
24970
  }
24848
24971
  function observationArtifactKindFromManifest(kind) {
24849
24972
  switch (kind) {
@@ -25543,6 +25666,7 @@ function payloadByteLength(value) {
25543
25666
 
25544
25667
  // src/cloud/session-proxy.ts
25545
25668
  var TEMPORARY_CLOUD_WORKSPACE_PREFIX = "opensteer-cloud-workspace-";
25669
+ var CLOUD_SESSION_REUSE_EXPIRY_SKEW_MS = 1e4;
25546
25670
  var CloudSessionProxy = class {
25547
25671
  rootPath;
25548
25672
  workspace;
@@ -25556,6 +25680,8 @@ var CloudSessionProxy = class {
25556
25680
  automation;
25557
25681
  workspaceStore;
25558
25682
  syncWorkspaceOnClose = false;
25683
+ liveSessionStateEstablished = false;
25684
+ storedInstrumentation = [];
25559
25685
  constructor(cloud, options = {}) {
25560
25686
  this.cloud = cloud;
25561
25687
  this.workspace = options.workspace;
@@ -25585,15 +25711,12 @@ var CloudSessionProxy = class {
25585
25711
  if (this.client === void 0 && this.sessionId === void 0 && persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
25586
25712
  this.bindClient(persisted);
25587
25713
  }
25588
- if (this.automation) {
25589
- try {
25590
- const sessionInfo = await this.automation.getSessionInfo();
25591
- return {
25592
- ...sessionInfo,
25593
- ...this.workspace === void 0 ? {} : { workspace: this.workspace }
25594
- };
25595
- } catch {
25596
- }
25714
+ const sessionInfo = this.automation ? await this.automation.getSessionInfo().catch(() => void 0) : void 0;
25715
+ if (sessionInfo !== void 0) {
25716
+ return {
25717
+ ...sessionInfo,
25718
+ ...this.workspace === void 0 ? {} : { workspace: this.workspace }
25719
+ };
25597
25720
  }
25598
25721
  return {
25599
25722
  provider: {
@@ -25705,12 +25828,26 @@ var CloudSessionProxy = class {
25705
25828
  return this.invokeSemanticOperation("session.cookies", input);
25706
25829
  }
25707
25830
  async route(input) {
25708
- await this.ensureSession();
25709
- return this.requireAutomation().route(input);
25831
+ const registration = await this.invokeBootstrapInstrumentationOperation(
25832
+ "instrumentation.route",
25833
+ (automation) => automation.route(input)
25834
+ );
25835
+ this.storedInstrumentation.push({
25836
+ kind: "route",
25837
+ input
25838
+ });
25839
+ return registration;
25710
25840
  }
25711
25841
  async interceptScript(input) {
25712
- await this.ensureSession();
25713
- return this.requireAutomation().interceptScript(input);
25842
+ const registration = await this.invokeBootstrapInstrumentationOperation(
25843
+ "instrumentation.intercept-script",
25844
+ (automation) => automation.interceptScript(input)
25845
+ );
25846
+ this.storedInstrumentation.push({
25847
+ kind: "intercept-script",
25848
+ input
25849
+ });
25850
+ return registration;
25714
25851
  }
25715
25852
  async getStorageSnapshot(input = {}) {
25716
25853
  return this.invokeSemanticOperation("session.storage", input);
@@ -25758,6 +25895,8 @@ var CloudSessionProxy = class {
25758
25895
  this.client = void 0;
25759
25896
  this.sessionId = void 0;
25760
25897
  this.semanticGrant = void 0;
25898
+ this.liveSessionStateEstablished = false;
25899
+ this.storedInstrumentation.length = 0;
25761
25900
  if (this.cleanupRootOnClose) {
25762
25901
  await promises.rm(this.rootPath, { recursive: true, force: true }).catch(() => void 0);
25763
25902
  }
@@ -25785,6 +25924,8 @@ var CloudSessionProxy = class {
25785
25924
  this.automation = void 0;
25786
25925
  this.sessionId = void 0;
25787
25926
  this.semanticGrant = void 0;
25927
+ this.liveSessionStateEstablished = false;
25928
+ this.storedInstrumentation.length = 0;
25788
25929
  if (syncError !== void 0) {
25789
25930
  throw syncError;
25790
25931
  }
@@ -25832,6 +25973,7 @@ var CloudSessionProxy = class {
25832
25973
  };
25833
25974
  await this.writePersistedSession(record);
25834
25975
  this.bindClient(record, session.initialGrants?.semantic);
25976
+ await this.restoreStoredInstrumentation();
25835
25977
  }
25836
25978
  async syncWorkspaceToCloud() {
25837
25979
  if (this.workspace === void 0) {
@@ -25843,6 +25985,7 @@ var CloudSessionProxy = class {
25843
25985
  bindClient(record, initialSemanticGrant) {
25844
25986
  this.sessionId = record.sessionId;
25845
25987
  this.semanticGrant = initialSemanticGrant?.kind === "semantic" ? initialSemanticGrant : void 0;
25988
+ this.liveSessionStateEstablished = false;
25846
25989
  this.client = new OpensteerSemanticRestClient({
25847
25990
  getBaseUrl: async () => (await this.ensureSemanticGrant()).url,
25848
25991
  getAuthorizationHeader: async () => `Bearer ${(await this.ensureSemanticGrant()).token}`,
@@ -25850,6 +25993,19 @@ var CloudSessionProxy = class {
25850
25993
  });
25851
25994
  this.automation = new OpensteerCloudAutomationClient(this.cloud, record.sessionId);
25852
25995
  }
25996
+ async restoreStoredInstrumentation() {
25997
+ if (this.storedInstrumentation.length === 0) {
25998
+ return;
25999
+ }
26000
+ const automation = this.requireAutomation();
26001
+ for (const registration of this.storedInstrumentation) {
26002
+ if (registration.kind === "route") {
26003
+ await automation.route(registration.input);
26004
+ } else {
26005
+ await automation.interceptScript(registration.input);
26006
+ }
26007
+ }
26008
+ }
25853
26009
  async ensureWorkspaceStore() {
25854
26010
  if (this.workspaceStore !== void 0) {
25855
26011
  return this.workspaceStore;
@@ -25872,13 +26028,22 @@ var CloudSessionProxy = class {
25872
26028
  async clearPersistedSession() {
25873
26029
  await clearPersistedSessionRecord(this.rootPath, "cloud").catch(() => void 0);
25874
26030
  }
26031
+ async invalidateSession() {
26032
+ await this.automation?.close().catch(() => void 0);
26033
+ this.automation = void 0;
26034
+ this.client = void 0;
26035
+ this.sessionId = void 0;
26036
+ this.semanticGrant = void 0;
26037
+ this.liveSessionStateEstablished = false;
26038
+ await this.clearPersistedSession();
26039
+ }
25875
26040
  async isReusableCloudSession(sessionId, timeout) {
25876
26041
  try {
25877
26042
  const session = await this.cloud.getSession(sessionId, {
25878
26043
  signal: timeout?.signal,
25879
26044
  timeoutMs: timeout?.remainingMs()
25880
26045
  });
25881
- return session.status !== "closed" && session.status !== "failed";
26046
+ return isReusableCloudSessionState(session);
25882
26047
  } catch (error) {
25883
26048
  if (isMissingCloudSessionError(error)) {
25884
26049
  return false;
@@ -25927,26 +26092,79 @@ var CloudSessionProxy = class {
25927
26092
  try {
25928
26093
  await this.ensureSemanticGrant(true);
25929
26094
  return true;
25930
- } catch {
26095
+ } catch (refreshError) {
26096
+ if (await this.resetStaleSession(refreshError)) {
26097
+ throw refreshError;
26098
+ }
25931
26099
  return false;
25932
26100
  }
25933
26101
  }
25934
26102
  async invokeSemanticOperation(operation, input, sessionInit = {}) {
25935
- return this.runOperationWithPolicy(operation, async (timeout) => {
26103
+ return this.runOperationWithSessionRecovery(operation, async (timeout) => {
25936
26104
  await this.ensureSession(sessionInit, timeout);
25937
26105
  await this.ensureSemanticGrant(false, timeout);
25938
- return this.requireClient().invoke(operation, input, {
26106
+ const output = await this.requireClient().invoke(operation, input, {
25939
26107
  signal: timeout.signal,
25940
26108
  timeoutMs: timeout.remainingMs()
25941
26109
  });
26110
+ this.noteSuccessfulLiveOperation(operation);
26111
+ return output;
25942
26112
  });
25943
26113
  }
25944
26114
  async invokeAutomationOperation(operation, invoke, sessionInit = {}) {
25945
- return this.runOperationWithPolicy(operation, async (timeout) => {
26115
+ return this.runOperationWithSessionRecovery(operation, async (timeout) => {
25946
26116
  await this.ensureSession(sessionInit, timeout);
25947
- return invoke(this.requireAutomation());
26117
+ const output = await invoke(this.requireAutomation());
26118
+ this.noteSuccessfulLiveOperation(operation);
26119
+ return output;
25948
26120
  });
25949
26121
  }
26122
+ async invokeBootstrapInstrumentationOperation(operation, invoke) {
26123
+ let recovered = false;
26124
+ while (true) {
26125
+ try {
26126
+ await this.ensureSession();
26127
+ return await invoke(this.requireAutomation());
26128
+ } catch (error) {
26129
+ const stale = await this.resetStaleSession(error);
26130
+ if (!stale || recovered || !this.canRecoverWithFreshSession(operation)) {
26131
+ throw error;
26132
+ }
26133
+ recovered = true;
26134
+ }
26135
+ }
26136
+ }
26137
+ async runOperationWithSessionRecovery(operation, invoke) {
26138
+ return this.runOperationWithPolicy(operation, async (timeout) => {
26139
+ let recovered = false;
26140
+ while (true) {
26141
+ try {
26142
+ return await invoke(timeout);
26143
+ } catch (error) {
26144
+ const stale = await this.resetStaleSession(error);
26145
+ if (!stale || recovered || !this.canRecoverWithFreshSession(operation)) {
26146
+ throw error;
26147
+ }
26148
+ recovered = true;
26149
+ }
26150
+ }
26151
+ });
26152
+ }
26153
+ async resetStaleSession(error) {
26154
+ if (!isRecoverableCloudSessionError(error)) {
26155
+ return false;
26156
+ }
26157
+ await this.invalidateSession();
26158
+ return true;
26159
+ }
26160
+ canRecoverWithFreshSession(operation) {
26161
+ return !this.liveSessionStateEstablished && isBootstrapRecoveryOperation(operation);
26162
+ }
26163
+ noteSuccessfulLiveOperation(operation) {
26164
+ if (operation === "session.open" || operation === "page.list" || operation === "page.new" || operation === "page.activate" || operation === "page.close" || operation === "page.goto" || operation === "page.evaluate" || operation === "page.add-init-script" || operation === "page.snapshot" || operation === "dom.click" || operation === "dom.hover" || operation === "dom.input" || operation === "dom.scroll" || operation === "dom.extract" || operation === "network.query" || operation === "network.detail" || operation === "interaction.capture" || operation === "interaction.get" || operation === "interaction.diff" || operation === "interaction.replay" || operation === "scripts.capture" || operation === "artifact.read" || operation === "scripts.beautify" || operation === "scripts.deobfuscate" || operation === "scripts.sandbox" || operation === "captcha.solve" || operation === "session.cookies" || operation === "session.storage" || operation === "session.state" || operation === "session.fetch" || operation === "computer.execute") {
26165
+ this.liveSessionStateEstablished = true;
26166
+ }
26167
+ }
25950
26168
  async runOperationWithPolicy(operation, invoke) {
25951
26169
  return runWithPolicyTimeout(this.policy.timeout, { operation }, invoke);
25952
26170
  }
@@ -25970,8 +26188,29 @@ function assertSupportedCloudBrowserMode(browser) {
25970
26188
  }
25971
26189
  }
25972
26190
  function isMissingCloudSessionError(error) {
26191
+ if (error instanceof OpensteerCloudRequestError) {
26192
+ return error.statusCode === 404 && (error.code === void 0 || error.code === "CLOUD_SESSION_NOT_FOUND");
26193
+ }
25973
26194
  return error instanceof Error && /\b404\b/.test(error.message);
25974
26195
  }
26196
+ function isRecoverableCloudSessionError(error) {
26197
+ if (!(error instanceof OpensteerCloudRequestError)) {
26198
+ return false;
26199
+ }
26200
+ if (error.statusCode === 404) {
26201
+ return error.code === void 0 || error.code === "CLOUD_SESSION_NOT_FOUND";
26202
+ }
26203
+ return error.statusCode === 409 && error.code === "CLOUD_SESSION_STALE";
26204
+ }
26205
+ function isBootstrapRecoveryOperation(operation) {
26206
+ return operation === "session.open" || operation === "instrumentation.route" || operation === "instrumentation.intercept-script";
26207
+ }
26208
+ function isReusableCloudSessionState(session) {
26209
+ if (session.status === "closing" || session.status === "closed" || session.status === "failed") {
26210
+ return false;
26211
+ }
26212
+ return !(typeof session.expiresAt === "number" && session.expiresAt <= Date.now() + CLOUD_SESSION_REUSE_EXPIRY_SKEW_MS);
26213
+ }
25975
26214
  function isLoopbackBaseUrl(baseUrl) {
25976
26215
  let url;
25977
26216
  try {
@@ -26133,6 +26372,25 @@ var SessionCookieJar = class {
26133
26372
  return this.cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join("; ");
26134
26373
  }
26135
26374
  };
26375
+ function createSdkProtocolError(error, fallbackMessage) {
26376
+ const normalized = normalizeThrownOpensteerError(error, fallbackMessage);
26377
+ return new OpensteerProtocolError(normalized.code, normalized.message, {
26378
+ cause: error,
26379
+ retriable: normalized.retriable,
26380
+ ...normalized.capability === void 0 ? {} : { capability: normalized.capability },
26381
+ ...normalized.details === void 0 ? {} : { details: normalized.details }
26382
+ });
26383
+ }
26384
+ async function wrapSdkError(operation, fn) {
26385
+ try {
26386
+ return await fn();
26387
+ } catch (error) {
26388
+ if (isOpensteerProtocolError(error)) {
26389
+ throw error;
26390
+ }
26391
+ throw createSdkProtocolError(error, `${operation} failed`);
26392
+ }
26393
+ }
26136
26394
  var Opensteer = class {
26137
26395
  runtime;
26138
26396
  browserManager;
@@ -26140,207 +26398,265 @@ var Opensteer = class {
26140
26398
  dom;
26141
26399
  network;
26142
26400
  constructor(options = {}) {
26143
- const environment = resolveOpensteerEnvironment(options.rootDir);
26144
- const { provider, engineName, ...runtimeOptions } = options;
26145
- const runtimeConfig = resolveOpensteerRuntimeConfig({
26146
- ...provider === void 0 ? {} : { provider },
26147
- environment
26148
- });
26149
- if (runtimeConfig.provider.mode === "cloud") {
26150
- this.browserManager = void 0;
26151
- this.runtime = createOpensteerSemanticRuntime({
26152
- ...provider === void 0 ? {} : { provider },
26153
- ...engineName === void 0 ? {} : { engine: engineName },
26154
- environment,
26155
- runtimeOptions
26156
- });
26157
- this.browser = createUnsupportedBrowserController();
26158
- } else {
26159
- this.browserManager = new OpensteerBrowserManager({
26160
- ...runtimeOptions.rootDir === void 0 ? {} : { rootDir: runtimeOptions.rootDir },
26161
- ...runtimeOptions.rootPath === void 0 ? {} : { rootPath: runtimeOptions.rootPath },
26162
- ...runtimeOptions.workspace === void 0 ? {} : { workspace: runtimeOptions.workspace },
26163
- ...engineName === void 0 ? {} : { engineName },
26164
- environment,
26165
- ...runtimeOptions.browser === void 0 ? {} : { browser: runtimeOptions.browser },
26166
- ...runtimeOptions.launch === void 0 ? {} : { launch: runtimeOptions.launch },
26167
- ...runtimeOptions.context === void 0 ? {} : { context: runtimeOptions.context }
26168
- });
26169
- this.runtime = createOpensteerSemanticRuntime({
26401
+ try {
26402
+ const environment = resolveOpensteerEnvironment(options.rootDir);
26403
+ const { provider, engineName, ...runtimeOptions } = options;
26404
+ const runtimeConfig = resolveOpensteerRuntimeConfig({
26170
26405
  ...provider === void 0 ? {} : { provider },
26171
- ...engineName === void 0 ? {} : { engine: engineName },
26172
- environment,
26173
- runtimeOptions: {
26174
- ...runtimeOptions,
26175
- rootPath: this.browserManager.rootPath,
26176
- cleanupRootOnClose: this.browserManager.cleanupRootOnDisconnect
26177
- }
26406
+ environment
26178
26407
  });
26179
- this.browser = {
26180
- status: () => this.browserManager.status(),
26181
- clone: (input) => this.browserManager.clonePersistentBrowser(input),
26182
- reset: () => this.browserManager.reset(),
26183
- delete: () => this.browserManager.delete()
26408
+ if (runtimeConfig.provider.mode === "cloud") {
26409
+ this.browserManager = void 0;
26410
+ this.runtime = createOpensteerSemanticRuntime({
26411
+ ...provider === void 0 ? {} : { provider },
26412
+ ...engineName === void 0 ? {} : { engine: engineName },
26413
+ environment,
26414
+ runtimeOptions
26415
+ });
26416
+ this.browser = createUnsupportedBrowserController();
26417
+ } else {
26418
+ this.browserManager = new OpensteerBrowserManager({
26419
+ ...runtimeOptions.rootDir === void 0 ? {} : { rootDir: runtimeOptions.rootDir },
26420
+ ...runtimeOptions.rootPath === void 0 ? {} : { rootPath: runtimeOptions.rootPath },
26421
+ ...runtimeOptions.workspace === void 0 ? {} : { workspace: runtimeOptions.workspace },
26422
+ ...engineName === void 0 ? {} : { engineName },
26423
+ environment,
26424
+ ...runtimeOptions.browser === void 0 ? {} : { browser: runtimeOptions.browser },
26425
+ ...runtimeOptions.launch === void 0 ? {} : { launch: runtimeOptions.launch },
26426
+ ...runtimeOptions.context === void 0 ? {} : { context: runtimeOptions.context }
26427
+ });
26428
+ this.runtime = createOpensteerSemanticRuntime({
26429
+ ...provider === void 0 ? {} : { provider },
26430
+ ...engineName === void 0 ? {} : { engine: engineName },
26431
+ environment,
26432
+ runtimeOptions: {
26433
+ ...runtimeOptions,
26434
+ rootPath: this.browserManager.rootPath,
26435
+ cleanupRootOnClose: this.browserManager.cleanupRootOnDisconnect
26436
+ }
26437
+ });
26438
+ this.browser = {
26439
+ status: () => wrapSdkError("browser.status", () => this.browserManager.status()),
26440
+ clone: (input) => wrapSdkError("browser.clone", () => this.browserManager.clonePersistentBrowser(input)),
26441
+ reset: () => wrapSdkError("browser.reset", () => this.browserManager.reset()),
26442
+ delete: () => wrapSdkError("browser.delete", () => this.browserManager.delete())
26443
+ };
26444
+ }
26445
+ this.dom = {
26446
+ click: (input) => this.click(input),
26447
+ hover: (input) => this.hover(input),
26448
+ input: (input) => this.input(input),
26449
+ scroll: (input) => this.scroll(input)
26184
26450
  };
26451
+ this.network = {
26452
+ query: (input = {}) => wrapSdkError("network.query", () => this.runtime.queryNetwork(input)),
26453
+ detail: (recordId, options2) => wrapSdkError(
26454
+ "network.detail",
26455
+ () => this.runtime.getNetworkDetail({ recordId, ...options2 })
26456
+ )
26457
+ };
26458
+ } catch (error) {
26459
+ if (isOpensteerProtocolError(error)) {
26460
+ throw error;
26461
+ }
26462
+ throw createSdkProtocolError(error, "Failed to initialize Opensteer");
26185
26463
  }
26186
- this.dom = {
26187
- click: (input) => this.click(input),
26188
- hover: (input) => this.hover(input),
26189
- input: (input) => this.input(input),
26190
- scroll: (input) => this.scroll(input)
26191
- };
26192
- this.network = {
26193
- query: (input = {}) => this.runtime.queryNetwork(input),
26194
- detail: (recordId, options2) => this.runtime.getNetworkDetail({ recordId, ...options2 })
26195
- };
26196
26464
  }
26197
26465
  async open(input = {}) {
26198
- return this.runtime.open(typeof input === "string" ? { url: input } : input);
26466
+ return wrapSdkError(
26467
+ "session.open",
26468
+ () => this.runtime.open(typeof input === "string" ? { url: input } : input)
26469
+ );
26199
26470
  }
26200
26471
  async info() {
26201
- return this.runtime.info();
26472
+ return wrapSdkError("session.info", () => this.runtime.info());
26202
26473
  }
26203
26474
  async listPages(input = {}) {
26204
- return this.runtime.listPages(input);
26475
+ return wrapSdkError("page.list", () => this.runtime.listPages(input));
26205
26476
  }
26206
26477
  async newPage(input = {}) {
26207
- return this.runtime.newPage(input);
26478
+ return wrapSdkError("page.new", () => this.runtime.newPage(input));
26208
26479
  }
26209
26480
  async activatePage(input) {
26210
- return this.runtime.activatePage(input);
26481
+ return wrapSdkError("page.activate", () => this.runtime.activatePage(input));
26211
26482
  }
26212
26483
  async closePage(input = {}) {
26213
- return this.runtime.closePage(input);
26484
+ return wrapSdkError("page.close", () => this.runtime.closePage(input));
26214
26485
  }
26215
26486
  async goto(url, options = {}) {
26216
- return this.runtime.goto({
26217
- url,
26218
- ...options
26219
- });
26487
+ return wrapSdkError(
26488
+ "page.goto",
26489
+ () => this.runtime.goto({
26490
+ url,
26491
+ ...options
26492
+ })
26493
+ );
26220
26494
  }
26221
26495
  async evaluate(input) {
26222
- const normalized = typeof input === "string" ? {
26223
- script: input
26224
- } : input;
26225
- return (await this.runtime.evaluate(normalized)).value;
26496
+ return wrapSdkError("page.evaluate", async () => {
26497
+ const normalized = typeof input === "string" ? {
26498
+ script: input
26499
+ } : input;
26500
+ return (await this.runtime.evaluate(normalized)).value;
26501
+ });
26226
26502
  }
26227
26503
  async addInitScript(input) {
26228
- return this.runtime.addInitScript(
26229
- typeof input === "string" ? {
26230
- script: input
26231
- } : input
26504
+ return wrapSdkError(
26505
+ "page.addInitScript",
26506
+ () => this.runtime.addInitScript(
26507
+ typeof input === "string" ? {
26508
+ script: input
26509
+ } : input
26510
+ )
26232
26511
  );
26233
26512
  }
26234
26513
  async click(input) {
26235
- const { button, clickCount, modifiers, ...target } = input;
26236
- return this.runtime.click({
26237
- ...normalizeTargetOptions(target),
26238
- ...button === void 0 ? {} : { button },
26239
- ...clickCount === void 0 ? {} : { clickCount },
26240
- ...modifiers === void 0 ? {} : { modifiers }
26514
+ return wrapSdkError("dom.click", () => {
26515
+ const { button, clickCount, modifiers, ...target } = input;
26516
+ return this.runtime.click({
26517
+ ...normalizeTargetOptions(target),
26518
+ ...button === void 0 ? {} : { button },
26519
+ ...clickCount === void 0 ? {} : { clickCount },
26520
+ ...modifiers === void 0 ? {} : { modifiers }
26521
+ });
26241
26522
  });
26242
26523
  }
26243
26524
  async hover(input) {
26244
- return this.runtime.hover(normalizeTargetOptions(input));
26525
+ return wrapSdkError("dom.hover", () => this.runtime.hover(normalizeTargetOptions(input)));
26245
26526
  }
26246
26527
  async input(input) {
26247
- return this.runtime.input({
26248
- ...normalizeTargetOptions(input),
26249
- text: input.text,
26250
- ...input.pressEnter === void 0 ? {} : { pressEnter: input.pressEnter }
26251
- });
26528
+ return wrapSdkError(
26529
+ "dom.input",
26530
+ () => this.runtime.input({
26531
+ ...normalizeTargetOptions(input),
26532
+ text: input.text,
26533
+ ...input.pressEnter === void 0 ? {} : { pressEnter: input.pressEnter }
26534
+ })
26535
+ );
26252
26536
  }
26253
26537
  async scroll(input) {
26254
- return this.runtime.scroll({
26255
- ...normalizeTargetOptions(input),
26256
- direction: input.direction,
26257
- amount: input.amount
26258
- });
26538
+ return wrapSdkError(
26539
+ "dom.scroll",
26540
+ () => this.runtime.scroll({
26541
+ ...normalizeTargetOptions(input),
26542
+ direction: input.direction,
26543
+ amount: input.amount
26544
+ })
26545
+ );
26259
26546
  }
26260
26547
  async extract(input) {
26261
- return (await this.runtime.extract(input)).data;
26548
+ return wrapSdkError("extract", async () => (await this.runtime.extract(input)).data);
26262
26549
  }
26263
26550
  async waitForPage(input = {}) {
26264
- const baseline = new Set((await this.runtime.listPages()).pages.map((page) => page.pageRef));
26265
- const timeoutAt = Date.now() + (input.timeoutMs ?? 3e4);
26266
- const pollIntervalMs = input.pollIntervalMs ?? 100;
26267
- while (true) {
26268
- const match = (await this.runtime.listPages()).pages.find((page) => {
26269
- if (baseline.has(page.pageRef)) {
26270
- return false;
26271
- }
26272
- if (input.openerPageRef !== void 0 && page.openerPageRef !== input.openerPageRef) {
26273
- return false;
26551
+ return wrapSdkError("page.waitForPage", async () => {
26552
+ const baseline = new Set((await this.runtime.listPages()).pages.map((page) => page.pageRef));
26553
+ const timeoutAt = Date.now() + (input.timeoutMs ?? 3e4);
26554
+ const pollIntervalMs = input.pollIntervalMs ?? 100;
26555
+ while (true) {
26556
+ const match = (await this.runtime.listPages()).pages.find((page) => {
26557
+ if (baseline.has(page.pageRef)) {
26558
+ return false;
26559
+ }
26560
+ if (input.openerPageRef !== void 0 && page.openerPageRef !== input.openerPageRef) {
26561
+ return false;
26562
+ }
26563
+ if (input.urlIncludes !== void 0 && !page.url.includes(input.urlIncludes)) {
26564
+ return false;
26565
+ }
26566
+ return true;
26567
+ });
26568
+ if (match !== void 0) {
26569
+ return match;
26274
26570
  }
26275
- if (input.urlIncludes !== void 0 && !page.url.includes(input.urlIncludes)) {
26276
- return false;
26571
+ if (Date.now() >= timeoutAt) {
26572
+ throw new OpensteerProtocolError("timeout", "waitForPage timed out");
26277
26573
  }
26278
- return true;
26279
- });
26280
- if (match !== void 0) {
26281
- return match;
26282
- }
26283
- if (Date.now() >= timeoutAt) {
26284
- throw new Error("waitForPage timed out");
26574
+ await delay3(pollIntervalMs);
26285
26575
  }
26286
- await delay3(pollIntervalMs);
26287
- }
26576
+ });
26288
26577
  }
26289
26578
  async cookies(domain) {
26290
- return new SessionCookieJar(
26291
- await this.runtime.getCookies(domain === void 0 ? {} : { domain })
26579
+ return wrapSdkError(
26580
+ "session.cookies",
26581
+ async () => new SessionCookieJar(await this.runtime.getCookies(domain === void 0 ? {} : { domain }))
26292
26582
  );
26293
26583
  }
26294
26584
  async storage(domain, type = "local") {
26295
- const snapshot = await this.runtime.getStorageSnapshot(domain === void 0 ? {} : { domain });
26296
- const domainSnapshot = pickStorageDomainSnapshot(snapshot, domain);
26297
- if (domainSnapshot === void 0) {
26298
- return {};
26299
- }
26300
- const entries = type === "local" ? domainSnapshot.localStorage : domainSnapshot.sessionStorage;
26301
- return Object.fromEntries(entries.map((entry) => [entry.key, entry.value]));
26585
+ return wrapSdkError("session.storage", async () => {
26586
+ const snapshot = await this.runtime.getStorageSnapshot(
26587
+ domain === void 0 ? {} : { domain }
26588
+ );
26589
+ const domainSnapshot = pickStorageDomainSnapshot(snapshot, domain);
26590
+ if (domainSnapshot === void 0) {
26591
+ return {};
26592
+ }
26593
+ const entries = type === "local" ? domainSnapshot.localStorage : domainSnapshot.sessionStorage;
26594
+ return Object.fromEntries(entries.map((entry) => [entry.key, entry.value]));
26595
+ });
26302
26596
  }
26303
26597
  async state(domain) {
26304
- return this.runtime.getBrowserState(domain === void 0 ? {} : { domain });
26598
+ return wrapSdkError(
26599
+ "session.state",
26600
+ () => this.runtime.getBrowserState(domain === void 0 ? {} : { domain })
26601
+ );
26305
26602
  }
26306
26603
  async fetch(url, options = {}) {
26307
- const input = buildFetchInput(url, options);
26308
- const result = await this.runtime.fetch(input);
26309
- if (result.response === void 0) {
26310
- throw new Error(result.note ?? `session.fetch did not produce a response for ${url}`);
26311
- }
26312
- return toResponse(result.response);
26604
+ return wrapSdkError("session.fetch", async () => {
26605
+ const input = buildFetchInput(url, options);
26606
+ const result = await this.runtime.fetch(input);
26607
+ if (result.response === void 0) {
26608
+ throw new OpensteerProtocolError(
26609
+ "operation-failed",
26610
+ result.note ?? `session.fetch did not produce a response for ${url}`
26611
+ );
26612
+ }
26613
+ return toResponse(result.response);
26614
+ });
26313
26615
  }
26314
26616
  async computerExecute(input) {
26315
- return this.runtime.computerExecute(input);
26617
+ return wrapSdkError("session.computerExecute", () => this.runtime.computerExecute(input));
26316
26618
  }
26317
26619
  async route(input) {
26318
- return this.requireOwnedInstrumentationRuntime("route").route(input);
26620
+ return wrapSdkError(
26621
+ "session.route",
26622
+ () => this.requireOwnedInstrumentationRuntime("route").route(input)
26623
+ );
26319
26624
  }
26320
26625
  async interceptScript(input) {
26321
- return this.requireOwnedInstrumentationRuntime("interceptScript").interceptScript(input);
26626
+ return wrapSdkError(
26627
+ "session.interceptScript",
26628
+ () => this.requireOwnedInstrumentationRuntime("interceptScript").interceptScript(input)
26629
+ );
26322
26630
  }
26323
26631
  async close() {
26324
- if (this.browserManager === void 0 || this.browserManager.mode === "temporary") {
26325
- return this.runtime.close();
26326
- }
26327
- const output = await this.runtime.close();
26328
- await this.browserManager.close();
26329
- return output;
26632
+ return wrapSdkError("session.close", async () => {
26633
+ if (this.browserManager === void 0 || this.browserManager.mode === "temporary") {
26634
+ return this.runtime.close();
26635
+ }
26636
+ const output = await this.runtime.close();
26637
+ await this.browserManager.close();
26638
+ return output;
26639
+ });
26330
26640
  }
26331
26641
  async disconnect() {
26332
- await this.runtime.disconnect();
26642
+ return wrapSdkError("session.disconnect", () => this.runtime.disconnect());
26333
26643
  }
26334
26644
  requireOwnedInstrumentationRuntime(method) {
26335
26645
  if (typeof this.runtime.route === "function" && typeof this.runtime.interceptScript === "function") {
26336
26646
  return this.runtime;
26337
26647
  }
26338
- throw new Error(`${method}() is not available for this session runtime.`);
26648
+ throw new OpensteerProtocolError(
26649
+ "unsupported-operation",
26650
+ `${method}() is not available for this session runtime.`
26651
+ );
26339
26652
  }
26340
26653
  };
26341
26654
  function createUnsupportedBrowserController() {
26342
26655
  const fail = async () => {
26343
- throw new Error("browser.* helpers are only available in local mode.");
26656
+ throw new OpensteerProtocolError(
26657
+ "unsupported-operation",
26658
+ "browser.* helpers are only available in local mode."
26659
+ );
26344
26660
  };
26345
26661
  return {
26346
26662
  status: fail,
@@ -26353,7 +26669,10 @@ function normalizeTargetOptions(input) {
26353
26669
  const hasElement = input.element !== void 0;
26354
26670
  const hasSelector = input.selector !== void 0;
26355
26671
  if (hasElement && hasSelector) {
26356
- throw new Error("Specify exactly one of element, selector, or persist.");
26672
+ throw new OpensteerProtocolError(
26673
+ "invalid-argument",
26674
+ "Specify exactly one of element, selector, or persist."
26675
+ );
26357
26676
  }
26358
26677
  if (hasElement) {
26359
26678
  return {
@@ -26376,7 +26695,10 @@ function normalizeTargetOptions(input) {
26376
26695
  };
26377
26696
  }
26378
26697
  if (input.persist === void 0) {
26379
- throw new Error("Specify exactly one of element, selector, or persist.");
26698
+ throw new OpensteerProtocolError(
26699
+ "invalid-argument",
26700
+ "Specify exactly one of element, selector, or persist."
26701
+ );
26380
26702
  }
26381
26703
  return {
26382
26704
  target: {
@@ -26448,6 +26770,7 @@ exports.Opensteer = Opensteer;
26448
26770
  exports.OpensteerAttachAmbiguousError = OpensteerAttachAmbiguousError;
26449
26771
  exports.OpensteerBrowserManager = OpensteerBrowserManager;
26450
26772
  exports.OpensteerCloudClient = OpensteerCloudClient;
26773
+ exports.OpensteerProtocolError = OpensteerProtocolError;
26451
26774
  exports.STABLE_PRIMARY_ATTR_KEYS = STABLE_PRIMARY_ATTR_KEYS;
26452
26775
  exports.assertProviderSupportsEngine = assertProviderSupportsEngine;
26453
26776
  exports.buildArrayFieldPathCandidates = buildArrayFieldPathCandidates;
@@ -26477,6 +26800,7 @@ exports.discoverLocalCdpBrowsers = discoverLocalCdpBrowsers;
26477
26800
  exports.hashDomDescriptorPersist = hashDomDescriptorPersist;
26478
26801
  exports.inspectCdpEndpoint = inspectCdpEndpoint;
26479
26802
  exports.isCurrentUrlField = isCurrentUrlField;
26803
+ exports.isOpensteerProtocolError = isOpensteerProtocolError;
26480
26804
  exports.isValidCssAttributeKey = isValidCssAttributeKey;
26481
26805
  exports.listLocalChromeProfiles = listLocalChromeProfiles;
26482
26806
  exports.manifestToExternalBinaryLocation = manifestToExternalBinaryLocation;
@@ -26485,6 +26809,7 @@ exports.normalizeObservabilityConfig = normalizeObservabilityConfig;
26485
26809
  exports.normalizeOpensteerEngineName = normalizeOpensteerEngineName;
26486
26810
  exports.normalizeOpensteerProviderMode = normalizeOpensteerProviderMode;
26487
26811
  exports.normalizeWorkspaceId = normalizeWorkspaceId;
26812
+ exports.opensteerErrorCodes = opensteerErrorCodes;
26488
26813
  exports.parseDomDescriptorRecord = parseDomDescriptorRecord;
26489
26814
  exports.parseExtractionDescriptorRecord = parseExtractionDescriptorRecord;
26490
26815
  exports.readPersistedCloudSessionRecord = readPersistedCloudSessionRecord;