opensteer 0.9.4 → 0.9.5

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
@@ -4445,10 +4445,10 @@ var opensteerDomScrollInputSchema = objectSchema(
4445
4445
  required: ["target", "direction", "amount"]
4446
4446
  }
4447
4447
  );
4448
- var opensteerExtractSchemaSchema = objectSchema(
4448
+ var opensteerExtractTemplateSchema = objectSchema(
4449
4449
  {},
4450
4450
  {
4451
- title: "OpensteerExtractSchema",
4451
+ title: "OpensteerExtractTemplate",
4452
4452
  additionalProperties: true
4453
4453
  }
4454
4454
  );
@@ -4456,13 +4456,13 @@ var opensteerDomExtractInputSchema = defineSchema({
4456
4456
  ...objectSchema(
4457
4457
  {
4458
4458
  persist: stringSchema(),
4459
- schema: opensteerExtractSchemaSchema
4459
+ template: opensteerExtractTemplateSchema
4460
4460
  },
4461
4461
  {
4462
4462
  title: "OpensteerDomExtractInput"
4463
4463
  }
4464
4464
  ),
4465
- anyOf: [defineSchema({ required: ["persist"] }), defineSchema({ required: ["schema"] })]
4465
+ anyOf: [defineSchema({ required: ["persist"] }), defineSchema({ required: ["template"] })]
4466
4466
  });
4467
4467
  var jsonValueSchema2 = recordSchema({}, { title: "JsonValueRecord" });
4468
4468
  var opensteerDomExtractOutputSchema = objectSchema(
@@ -6912,6 +6912,7 @@ var defaultNavigationSettleObserver = {
6912
6912
  return false;
6913
6913
  }
6914
6914
  try {
6915
+ const startedAt = Date.now();
6915
6916
  await input.engine.waitForPostLoadQuiet({
6916
6917
  pageRef: input.pageRef,
6917
6918
  timeoutMs: effectiveTimeout,
@@ -6919,9 +6920,13 @@ var defaultNavigationSettleObserver = {
6919
6920
  captureWindowMs: Math.min(NAVIGATION_POST_LOAD_CAPTURE_WINDOW_MS, effectiveTimeout),
6920
6921
  signal: input.signal
6921
6922
  });
6923
+ const visualTimeout = Math.max(0, effectiveTimeout - (Date.now() - startedAt));
6924
+ if (visualTimeout <= 0) {
6925
+ return true;
6926
+ }
6922
6927
  await input.engine.waitForVisualStability({
6923
6928
  pageRef: input.pageRef,
6924
- timeoutMs: effectiveTimeout,
6929
+ timeoutMs: visualTimeout,
6925
6930
  settleMs: profile.settleMs,
6926
6931
  scope: profile.scope
6927
6932
  });
@@ -11200,9 +11205,9 @@ function isPersistedObjectNode(node) {
11200
11205
  }
11201
11206
 
11202
11207
  // ../runtime-core/src/sdk/extraction.ts
11203
- function assertValidOpensteerExtractionSchemaRoot(schema) {
11204
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
11205
- throw new Error("Invalid extraction schema: expected a JSON object at the top level.");
11208
+ function assertValidOpensteerExtractionTemplateRoot(template) {
11209
+ if (!template || typeof template !== "object" || Array.isArray(template)) {
11210
+ throw new Error("Invalid extraction template: expected a JSON object at the top level.");
11206
11211
  }
11207
11212
  }
11208
11213
  function isPersistedOpensteerExtractionValueNode2(value) {
@@ -11224,12 +11229,12 @@ function isPersistedOpensteerExtractionArrayNode2(value) {
11224
11229
  return "$array" in value;
11225
11230
  }
11226
11231
  async function compileOpensteerExtractionFieldTargets(options) {
11227
- assertValidOpensteerExtractionSchemaRoot(options.schema);
11232
+ assertValidOpensteerExtractionTemplateRoot(options.template);
11228
11233
  const fields = [];
11229
- await collectFieldTargetsFromSchemaObject({
11234
+ await collectFieldTargetsFromTemplateObject({
11230
11235
  dom: options.dom,
11231
11236
  pageRef: options.pageRef,
11232
- value: options.schema,
11237
+ value: options.template,
11233
11238
  path: "",
11234
11239
  fields,
11235
11240
  insideArray: false
@@ -11281,13 +11286,13 @@ function createOpensteerExtractionDescriptorStore(options) {
11281
11286
  }
11282
11287
  return new MemoryOpensteerExtractionDescriptorStore(namespace);
11283
11288
  }
11284
- async function collectFieldTargetsFromSchemaObject(options) {
11289
+ async function collectFieldTargetsFromTemplateObject(options) {
11285
11290
  for (const [key, childValue] of Object.entries(options.value)) {
11286
11291
  const normalizedKey = normalizeKey(key);
11287
11292
  if (!normalizedKey) {
11288
11293
  continue;
11289
11294
  }
11290
- await collectFieldTargetsFromSchemaValue({
11295
+ await collectFieldTargetsFromTemplateValue({
11291
11296
  dom: options.dom,
11292
11297
  pageRef: options.pageRef,
11293
11298
  value: childValue,
@@ -11297,8 +11302,8 @@ async function collectFieldTargetsFromSchemaObject(options) {
11297
11302
  });
11298
11303
  }
11299
11304
  }
11300
- async function collectFieldTargetsFromSchemaValue(options) {
11301
- const normalizedField = normalizeSchemaField(options.value);
11305
+ async function collectFieldTargetsFromTemplateValue(options) {
11306
+ const normalizedField = normalizeTemplateField(options.value);
11302
11307
  if (normalizedField !== null) {
11303
11308
  options.fields.push(
11304
11309
  await compileFieldTarget({
@@ -11313,12 +11318,12 @@ async function collectFieldTargetsFromSchemaValue(options) {
11313
11318
  if (Array.isArray(options.value)) {
11314
11319
  if (options.insideArray) {
11315
11320
  throw new Error(
11316
- `Nested arrays are not supported in extraction schema at "${labelForPath(options.path)}".`
11321
+ `Nested arrays are not supported in extraction template at "${labelForPath(options.path)}".`
11317
11322
  );
11318
11323
  }
11319
11324
  if (options.value.length === 0) {
11320
11325
  throw new Error(
11321
- `Extraction array "${labelForPath(options.path)}" must include at least one representative item.`
11326
+ `Extraction array "${labelForPath(options.path)}" must include at least one representative template item.`
11322
11327
  );
11323
11328
  }
11324
11329
  for (let index = 0; index < options.value.length; index += 1) {
@@ -11329,7 +11334,7 @@ async function collectFieldTargetsFromSchemaValue(options) {
11329
11334
  );
11330
11335
  }
11331
11336
  const fieldCountBeforeItem = options.fields.length;
11332
- await collectFieldTargetsFromSchemaObject({
11337
+ await collectFieldTargetsFromTemplateObject({
11333
11338
  dom: options.dom,
11334
11339
  pageRef: options.pageRef,
11335
11340
  value: itemValue,
@@ -11340,7 +11345,7 @@ async function collectFieldTargetsFromSchemaValue(options) {
11340
11345
  const itemFields = options.fields.slice(fieldCountBeforeItem);
11341
11346
  if (!itemFields.some((field) => !("source" in field))) {
11342
11347
  throw new Error(
11343
- `Extraction array "${labelForPath(options.path)}" item ${String(index)} must include at least one element- or selector-backed field.`
11348
+ `Extraction array "${labelForPath(options.path)}" item ${String(index)} must include at least one element number or selector field.`
11344
11349
  );
11345
11350
  }
11346
11351
  }
@@ -11348,10 +11353,10 @@ async function collectFieldTargetsFromSchemaValue(options) {
11348
11353
  }
11349
11354
  if (!options.value || typeof options.value !== "object") {
11350
11355
  throw new Error(
11351
- `Invalid extraction schema value at "${labelForPath(options.path)}": expected an object, array, or field descriptor.`
11356
+ `Invalid extraction template value at "${labelForPath(options.path)}": expected an object, array, or field descriptor.`
11352
11357
  );
11353
11358
  }
11354
- await collectFieldTargetsFromSchemaObject({
11359
+ await collectFieldTargetsFromTemplateObject({
11355
11360
  dom: options.dom,
11356
11361
  pageRef: options.pageRef,
11357
11362
  value: options.value,
@@ -11383,7 +11388,7 @@ async function compileFieldTarget(options) {
11383
11388
  path: await resolveSelectorFieldPath({
11384
11389
  dom: options.dom,
11385
11390
  pageRef: options.pageRef,
11386
- selector: `[c="${String(options.field.element)}"]`
11391
+ selector: `[c="${String(options.field.c)}"]`
11387
11392
  }),
11388
11393
  ...options.field.attribute === void 0 ? {} : { attribute: options.field.attribute }
11389
11394
  };
@@ -11684,24 +11689,29 @@ function countNonNullLeaves(value) {
11684
11689
  }
11685
11690
  return Object.values(value).reduce((sum, item) => sum + countNonNullLeaves(item), 0);
11686
11691
  }
11687
- function normalizeSchemaField(value) {
11692
+ function normalizeTemplateField(value) {
11693
+ if (typeof value === "number") {
11694
+ return {
11695
+ c: normalizeExtractionCounter(value)
11696
+ };
11697
+ }
11688
11698
  if (!value || typeof value !== "object" || Array.isArray(value)) {
11689
11699
  return null;
11690
11700
  }
11691
11701
  const raw = value;
11692
- const hasElement = raw.element !== void 0;
11702
+ const hasCounter = raw.c !== void 0 || raw.element !== void 0;
11693
11703
  const hasSelector = raw.selector !== void 0;
11694
11704
  const hasSource = raw.source !== void 0;
11695
- const targetCount = Number(hasElement) + Number(hasSelector) + Number(hasSource);
11705
+ const targetCount = Number(hasCounter) + Number(hasSelector) + Number(hasSource);
11696
11706
  if (targetCount === 0) {
11697
11707
  return null;
11698
11708
  }
11699
11709
  if (targetCount !== 1) {
11700
11710
  throw new Error(
11701
- "Extraction field descriptors must specify exactly one of element, selector, or source."
11711
+ "Extraction field descriptors must specify exactly one of c/element, selector, or source."
11702
11712
  );
11703
11713
  }
11704
- const attribute = raw.attribute === void 0 ? void 0 : normalizeNonEmptyString2("attribute", raw.attribute);
11714
+ const attribute = raw.attr !== void 0 ? normalizeNonEmptyString2("attr", raw.attr) : raw.attribute === void 0 ? void 0 : normalizeNonEmptyString2("attribute", raw.attribute);
11705
11715
  if (hasSource) {
11706
11716
  if (raw.source !== "current_url") {
11707
11717
  throw new Error(`Unsupported extraction source "${String(raw.source)}".`);
@@ -11716,17 +11726,20 @@ function normalizeSchemaField(value) {
11716
11726
  ...attribute === void 0 ? {} : { attribute }
11717
11727
  };
11718
11728
  }
11719
- const element = Number(raw.element);
11720
- if (!Number.isInteger(element) || element < 1) {
11721
- throw new Error(
11722
- `Extraction field element must be a positive integer, received ${String(raw.element)}.`
11723
- );
11724
- }
11725
11729
  return {
11726
- element,
11730
+ c: normalizeExtractionCounter(raw.c ?? raw.element),
11727
11731
  ...attribute === void 0 ? {} : { attribute }
11728
11732
  };
11729
11733
  }
11734
+ function normalizeExtractionCounter(value) {
11735
+ const counter = Number(value);
11736
+ if (!Number.isInteger(counter) || counter < 1) {
11737
+ throw new Error(
11738
+ `Extraction element number must be a positive integer, received ${String(value)}.`
11739
+ );
11740
+ }
11741
+ return counter;
11742
+ }
11730
11743
  function normalizeNamespace(namespace) {
11731
11744
  const normalized = String(namespace ?? "default").trim();
11732
11745
  return normalized.length === 0 ? "default" : normalized;
@@ -11757,7 +11770,7 @@ function parseExtractionDescriptorRecord(record) {
11757
11770
  kind: "dom-extraction",
11758
11771
  persist: raw.persist,
11759
11772
  root,
11760
- ...typeof raw.schemaHash === "string" ? { schemaHash: raw.schemaHash } : {},
11773
+ ...typeof raw.templateHash === "string" ? { templateHash: raw.templateHash } : typeof raw.schemaHash === "string" ? { templateHash: raw.schemaHash } : {},
11761
11774
  ...typeof raw.sourceUrl === "string" ? { sourceUrl: raw.sourceUrl } : {}
11762
11775
  }
11763
11776
  };
@@ -11843,7 +11856,7 @@ var FilesystemOpensteerExtractionDescriptorStore = class {
11843
11856
  kind: "dom-extraction",
11844
11857
  persist: input.persist,
11845
11858
  root: input.root,
11846
- ...input.schemaHash === void 0 ? {} : { schemaHash: input.schemaHash },
11859
+ ...input.templateHash === void 0 ? {} : { templateHash: input.templateHash },
11847
11860
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
11848
11861
  };
11849
11862
  const key = persistKey(this.namespace, input.persist);
@@ -11892,7 +11905,7 @@ var MemoryOpensteerExtractionDescriptorStore = class {
11892
11905
  kind: "dom-extraction",
11893
11906
  persist: input.persist,
11894
11907
  root: input.root,
11895
- ...input.schemaHash === void 0 ? {} : { schemaHash: input.schemaHash },
11908
+ ...input.templateHash === void 0 ? {} : { templateHash: input.templateHash },
11896
11909
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
11897
11910
  };
11898
11911
  const key = persistKey(this.namespace, input.persist);
@@ -15691,7 +15704,7 @@ function resolveCloudConfig(input = {}) {
15691
15704
 
15692
15705
  // ../runtime-core/package.json
15693
15706
  var package_default = {
15694
- version: "0.2.3"};
15707
+ version: "0.2.4"};
15695
15708
 
15696
15709
  // ../runtime-core/src/version.ts
15697
15710
  var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
@@ -16737,10 +16750,19 @@ var VOID_TAGS = /* @__PURE__ */ new Set([
16737
16750
  // ../runtime-core/src/sdk/snapshot/cleaner.ts
16738
16751
  var STRIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "noscript", "meta", "link", "template"]);
16739
16752
  var TEXT_ATTR_MAX = 150;
16740
- var URL_ATTR_MAX = 500;
16741
- var URL_ATTRS = /* @__PURE__ */ new Set(["href", "src", "srcset"]);
16753
+ var SRCSET_ATTR_MAX = 160;
16754
+ var MIDDLE_TRUNCATED_URL_ATTRS = /* @__PURE__ */ new Set(["href", "src"]);
16742
16755
  var TEXT_ATTRS = /* @__PURE__ */ new Set(["alt", "title", "aria-label", "placeholder", "value"]);
16743
- var TRUNCATION_SUFFIX = " [truncated]";
16756
+ var TRUNCATION_SUFFIX = "...";
16757
+ var MIDDLE_TRUNCATION_MARKER = "...";
16758
+ var MIDDLE_TRUNCATION_HEAD_MAX = 40;
16759
+ var MIDDLE_TRUNCATION_TAIL_MAX = 20;
16760
+ var SRCSET_CANDIDATE_HEAD_MAX = 36;
16761
+ var SRCSET_CANDIDATE_TAIL_MAX = 12;
16762
+ var SRCSET_COMPACT_CANDIDATE_HEAD_MAX = 20;
16763
+ var SRCSET_COMPACT_CANDIDATE_TAIL_MAX = 8;
16764
+ var SRCSET_FALLBACK_HEAD_MAX = 56;
16765
+ var SRCSET_FALLBACK_TAIL_MAX = 20;
16744
16766
  var NOISE_SELECTORS = [
16745
16767
  `[${OPENSTEER_HIDDEN_ATTR}]`,
16746
16768
  "[hidden]",
@@ -16803,19 +16825,260 @@ function truncateValue(value, max) {
16803
16825
  }
16804
16826
  return `${head}${TRUNCATION_SUFFIX}`;
16805
16827
  }
16828
+ function takeValueWithinSerializedLengthFromEnd(value, max) {
16829
+ let serializedLength = 0;
16830
+ const chars = [];
16831
+ for (let index = value.length - 1; index >= 0; index -= 1) {
16832
+ const char = value[index];
16833
+ let nextLength = 1;
16834
+ if (char === "&") {
16835
+ nextLength = 5;
16836
+ } else if (char === "<" || char === ">") {
16837
+ nextLength = 4;
16838
+ } else if (char === '"') {
16839
+ nextLength = 6;
16840
+ }
16841
+ if (serializedLength + nextLength > max) {
16842
+ break;
16843
+ }
16844
+ chars.push(char);
16845
+ serializedLength += nextLength;
16846
+ }
16847
+ return chars.reverse().join("");
16848
+ }
16849
+ function truncateValueInMiddle(value, headMax, tailMax, marker = MIDDLE_TRUNCATION_MARKER) {
16850
+ const markerLength = getSerializedLength(marker);
16851
+ const max = headMax + markerLength + tailMax;
16852
+ if (getSerializedLength(value) <= max) {
16853
+ return value;
16854
+ }
16855
+ const head = takeValueWithinSerializedLength(value, headMax).replace(/\s+$/u, "");
16856
+ const tail = takeValueWithinSerializedLengthFromEnd(value, tailMax).replace(/^\s+/u, "");
16857
+ if (head.length === 0) {
16858
+ return tail.length === 0 ? marker : `${marker}${tail}`;
16859
+ }
16860
+ if (tail.length === 0) {
16861
+ return `${head}${marker}`;
16862
+ }
16863
+ return `${head}${marker}${tail}`;
16864
+ }
16806
16865
  function getAttrLimit(attr) {
16807
- if (URL_ATTRS.has(attr)) {
16808
- return URL_ATTR_MAX;
16866
+ if (attr === "srcset") {
16867
+ return SRCSET_ATTR_MAX;
16809
16868
  }
16810
16869
  if (TEXT_ATTRS.has(attr)) {
16811
16870
  return TEXT_ATTR_MAX;
16812
16871
  }
16813
16872
  return void 0;
16814
16873
  }
16874
+ function shouldBoundAttr(attr) {
16875
+ return MIDDLE_TRUNCATED_URL_ATTRS.has(attr) || getAttrLimit(attr) !== void 0;
16876
+ }
16815
16877
  function setBoundedAttr(el, attr, value) {
16878
+ if (MIDDLE_TRUNCATED_URL_ATTRS.has(attr)) {
16879
+ el.attr(
16880
+ attr,
16881
+ truncateValueInMiddle(value, MIDDLE_TRUNCATION_HEAD_MAX, MIDDLE_TRUNCATION_TAIL_MAX)
16882
+ );
16883
+ return;
16884
+ }
16816
16885
  const limit = getAttrLimit(attr);
16886
+ if (attr === "srcset" && limit !== void 0) {
16887
+ el.attr(attr, truncateSrcsetValue(value, limit));
16888
+ return;
16889
+ }
16817
16890
  el.attr(attr, limit === void 0 ? value : truncateValue(value, limit));
16818
16891
  }
16892
+ function truncateSrcsetValue(value, max) {
16893
+ if (getSerializedLength(value) <= max) {
16894
+ return value;
16895
+ }
16896
+ const candidates = parseSrcsetCandidates2(value);
16897
+ if (candidates.length === 0) {
16898
+ return truncateValueInMiddle(value, SRCSET_FALLBACK_HEAD_MAX, SRCSET_FALLBACK_TAIL_MAX);
16899
+ }
16900
+ for (const [headMax, tailMax, includeBest] of [
16901
+ [SRCSET_CANDIDATE_HEAD_MAX, SRCSET_CANDIDATE_TAIL_MAX, true],
16902
+ [SRCSET_COMPACT_CANDIDATE_HEAD_MAX, SRCSET_COMPACT_CANDIDATE_TAIL_MAX, true],
16903
+ [SRCSET_COMPACT_CANDIDATE_HEAD_MAX, SRCSET_COMPACT_CANDIDATE_TAIL_MAX, false]
16904
+ ]) {
16905
+ const compact = buildTruncatedSrcsetValue(candidates, headMax, tailMax, includeBest);
16906
+ if (getSerializedLength(compact) <= max) {
16907
+ return compact;
16908
+ }
16909
+ }
16910
+ return truncateValueInMiddle(value, SRCSET_FALLBACK_HEAD_MAX, SRCSET_FALLBACK_TAIL_MAX);
16911
+ }
16912
+ function buildTruncatedSrcsetValue(candidates, headMax, tailMax, includeBest) {
16913
+ const kept = getPreferredSrcsetCandidateIndices(candidates, includeBest);
16914
+ const parts = [];
16915
+ let previousIndex;
16916
+ for (const candidateIndex of kept) {
16917
+ if (previousIndex !== void 0 && candidateIndex - previousIndex > 1) {
16918
+ parts.push(MIDDLE_TRUNCATION_MARKER);
16919
+ }
16920
+ parts.push(formatSrcsetCandidate(candidates[candidateIndex], headMax, tailMax));
16921
+ previousIndex = candidateIndex;
16922
+ }
16923
+ return parts.join(", ");
16924
+ }
16925
+ function getPreferredSrcsetCandidateIndices(candidates, includeBest) {
16926
+ if (candidates.length === 0) {
16927
+ return [];
16928
+ }
16929
+ const kept = /* @__PURE__ */ new Set([0, candidates.length - 1]);
16930
+ if (includeBest) {
16931
+ kept.add(pickBestSrcsetCandidateIndex(candidates));
16932
+ }
16933
+ return [...kept].filter((index) => index >= 0 && index < candidates.length).sort((a, b) => a - b);
16934
+ }
16935
+ function pickBestSrcsetCandidateIndex(candidates) {
16936
+ let bestWidthIndex = -1;
16937
+ let bestWidth = -1;
16938
+ let bestDensityIndex = -1;
16939
+ let bestDensity = -1;
16940
+ for (let index = 0; index < candidates.length; index += 1) {
16941
+ const candidate = candidates[index];
16942
+ if (typeof candidate.width === "number" && Number.isFinite(candidate.width) && candidate.width > bestWidth) {
16943
+ bestWidth = candidate.width;
16944
+ bestWidthIndex = index;
16945
+ }
16946
+ if (typeof candidate.density === "number" && Number.isFinite(candidate.density) && candidate.density > bestDensity) {
16947
+ bestDensity = candidate.density;
16948
+ bestDensityIndex = index;
16949
+ }
16950
+ }
16951
+ if (bestWidthIndex >= 0) {
16952
+ return bestWidthIndex;
16953
+ }
16954
+ if (bestDensityIndex >= 0) {
16955
+ return bestDensityIndex;
16956
+ }
16957
+ return candidates.length - 1;
16958
+ }
16959
+ function formatSrcsetCandidate(candidate, headMax, tailMax) {
16960
+ const url = truncateValueInMiddle(candidate.url, headMax, tailMax);
16961
+ return candidate.descriptorText ? `${url} ${candidate.descriptorText}` : url;
16962
+ }
16963
+ function parseSrcsetCandidates2(raw) {
16964
+ const text = raw.trim();
16965
+ if (!text) {
16966
+ return [];
16967
+ }
16968
+ const out = [];
16969
+ let index = 0;
16970
+ while (index < text.length) {
16971
+ index = skipSrcsetSeparators(text, index);
16972
+ if (index >= text.length) {
16973
+ break;
16974
+ }
16975
+ const urlToken = readSrcsetUrlToken(text, index);
16976
+ index = urlToken.nextIndex;
16977
+ const url = urlToken.value.trim();
16978
+ if (!url) {
16979
+ continue;
16980
+ }
16981
+ index = skipSrcsetWhitespace(text, index);
16982
+ const descriptors = [];
16983
+ while (index < text.length && text[index] !== ",") {
16984
+ const descriptorToken = readSrcsetDescriptorToken(text, index);
16985
+ if (!descriptorToken.value) {
16986
+ index = descriptorToken.nextIndex;
16987
+ continue;
16988
+ }
16989
+ descriptors.push(descriptorToken.value);
16990
+ index = descriptorToken.nextIndex;
16991
+ index = skipSrcsetWhitespace(text, index);
16992
+ }
16993
+ if (index < text.length && text[index] === ",") {
16994
+ index += 1;
16995
+ }
16996
+ let width = null;
16997
+ let density = null;
16998
+ for (const descriptor of descriptors) {
16999
+ const token = descriptor.trim().toLowerCase();
17000
+ if (!token) {
17001
+ continue;
17002
+ }
17003
+ const widthMatch = token.match(/^(\d+)w$/);
17004
+ if (widthMatch) {
17005
+ const parsed = Number.parseInt(widthMatch[1], 10);
17006
+ if (Number.isFinite(parsed)) {
17007
+ width = parsed;
17008
+ }
17009
+ continue;
17010
+ }
17011
+ const densityMatch = token.match(/^(\d*\.?\d+)x$/);
17012
+ if (densityMatch) {
17013
+ const parsed = Number.parseFloat(densityMatch[1]);
17014
+ if (Number.isFinite(parsed)) {
17015
+ density = parsed;
17016
+ }
17017
+ }
17018
+ }
17019
+ out.push({
17020
+ url,
17021
+ descriptorText: descriptors.join(" "),
17022
+ width,
17023
+ density
17024
+ });
17025
+ }
17026
+ return out;
17027
+ }
17028
+ function skipSrcsetWhitespace(value, index) {
17029
+ let cursor = index;
17030
+ while (cursor < value.length && /\s/u.test(value[cursor])) {
17031
+ cursor += 1;
17032
+ }
17033
+ return cursor;
17034
+ }
17035
+ function skipSrcsetSeparators(value, index) {
17036
+ let cursor = skipSrcsetWhitespace(value, index);
17037
+ while (cursor < value.length && value[cursor] === ",") {
17038
+ cursor += 1;
17039
+ cursor = skipSrcsetWhitespace(value, cursor);
17040
+ }
17041
+ return cursor;
17042
+ }
17043
+ function readSrcsetUrlToken(value, index) {
17044
+ let cursor = index;
17045
+ let out = "";
17046
+ const isDataUrl = value.slice(index, index + 5).toLowerCase().startsWith("data:");
17047
+ while (cursor < value.length) {
17048
+ const char = value[cursor];
17049
+ if (/\s/u.test(char)) {
17050
+ break;
17051
+ }
17052
+ if (char === "," && !isDataUrl) {
17053
+ break;
17054
+ }
17055
+ out += char;
17056
+ cursor += 1;
17057
+ }
17058
+ if (isDataUrl && out.endsWith(",") && cursor < value.length) {
17059
+ out = out.slice(0, -1);
17060
+ }
17061
+ return {
17062
+ value: out,
17063
+ nextIndex: cursor
17064
+ };
17065
+ }
17066
+ function readSrcsetDescriptorToken(value, index) {
17067
+ let cursor = skipSrcsetWhitespace(value, index);
17068
+ let out = "";
17069
+ while (cursor < value.length) {
17070
+ const char = value[cursor];
17071
+ if (char === "," || /\s/u.test(char)) {
17072
+ break;
17073
+ }
17074
+ out += char;
17075
+ cursor += 1;
17076
+ }
17077
+ return {
17078
+ value: out.trim(),
17079
+ nextIndex: cursor
17080
+ };
17081
+ }
16819
17082
  function removeNoise($) {
16820
17083
  for (const tag of STRIP_TAGS) {
16821
17084
  $(tag).remove();
@@ -16840,38 +17103,68 @@ function markInlineSelfHiddenFallback($) {
16840
17103
  });
16841
17104
  }
16842
17105
  function pruneSelfHiddenNodes($) {
16843
- const nodes = [];
16844
- $(`[${OPENSTEER_SELF_HIDDEN_ATTR}]`).each(function collectSelfHiddenNodes() {
16845
- nodes.push($(this));
16846
- });
16847
- nodes.sort((left, right) => right.parents().length - left.parents().length);
16848
- for (const el of nodes) {
16849
- if (!el[0]) {
17106
+ for (const node of getElementsInReverseDocumentOrder($)) {
17107
+ if (node.attribs?.[OPENSTEER_SELF_HIDDEN_ATTR] === void 0) {
16850
17108
  continue;
16851
17109
  }
17110
+ const el = $(node);
16852
17111
  el.contents().each(function removeSelfHiddenText() {
16853
17112
  if (this.type === "text") {
16854
17113
  $(this).remove();
16855
17114
  }
16856
17115
  });
16857
- if (el.children().length === 0) {
17116
+ if (!hasElementChildren(node)) {
16858
17117
  el.remove();
16859
17118
  }
16860
17119
  }
16861
17120
  }
16862
- function hasDirectText($, el) {
16863
- return el.contents().filter(function hasDirectNodeText() {
16864
- return this.type === "text" && $(this).text().trim() !== "";
16865
- }).length > 0;
17121
+ function getChildNodes(node) {
17122
+ return node?.children ?? [];
17123
+ }
17124
+ function isElementLikeNode(node) {
17125
+ return node?.type === "tag" || node?.type === "script" || node?.type === "style";
17126
+ }
17127
+ function hasDirectText(node) {
17128
+ if (!node) {
17129
+ return false;
17130
+ }
17131
+ for (const child of getChildNodes(node)) {
17132
+ if (child.type === "text" && (child.data || "").trim() !== "") {
17133
+ return true;
17134
+ }
17135
+ }
17136
+ return false;
17137
+ }
17138
+ function hasElementChildren(node) {
17139
+ if (!node) {
17140
+ return false;
17141
+ }
17142
+ for (const child of getChildNodes(node)) {
17143
+ if (isElementLikeNode(child)) {
17144
+ return true;
17145
+ }
17146
+ }
17147
+ return false;
16866
17148
  }
16867
- function hasTextDeep(el) {
16868
- return el.text().trim().length > 0;
17149
+ function hasTextDeepNode(node) {
17150
+ if (!node) {
17151
+ return false;
17152
+ }
17153
+ if (node.type === "text") {
17154
+ return (node.data || "").trim() !== "";
17155
+ }
17156
+ for (const child of getChildNodes(node)) {
17157
+ if (hasTextDeepNode(child)) {
17158
+ return true;
17159
+ }
17160
+ }
17161
+ return false;
16869
17162
  }
16870
17163
  function hasActionLabel(attrs) {
16871
17164
  return typeof attrs["aria-label"] === "string" && attrs["aria-label"].trim() !== "" || typeof attrs["aria-labelledby"] === "string" && attrs["aria-labelledby"].trim() !== "" || typeof attrs["aria-describedby"] === "string" && attrs["aria-describedby"].trim() !== "" || typeof attrs.title === "string" && attrs.title.trim() !== "" || typeof attrs.placeholder === "string" && attrs.placeholder.trim() !== "" || typeof attrs.value === "string" && attrs.value.trim() !== "";
16872
17165
  }
16873
17166
  function unwrapActionNode($, el) {
16874
- if (hasTextDeep(el)) {
17167
+ if (hasTextDeepNode(el[0])) {
16875
17168
  if (el.prev().length > 0) {
16876
17169
  el.before(" ");
16877
17170
  }
@@ -16892,7 +17185,7 @@ function stripToAttrs(el, keep) {
16892
17185
  if (typeof value !== "string") {
16893
17186
  continue;
16894
17187
  }
16895
- if (getAttrLimit(attr) !== void 0) {
17188
+ if (shouldBoundAttr(attr)) {
16896
17189
  setBoundedAttr(el, attr, value);
16897
17190
  }
16898
17191
  }
@@ -16910,6 +17203,9 @@ function restoreBoundedAttr(el, attr, value) {
16910
17203
  function deduplicateImages(html) {
16911
17204
  const seen = /* @__PURE__ */ new Set();
16912
17205
  return html.replace(/<img\b([^>]*)>/gi, (full, attrContent) => {
17206
+ if (/\bc\s*=/.test(attrContent)) {
17207
+ return full;
17208
+ }
16913
17209
  const srcMatch = attrContent.match(/\bsrc\s*=\s*(["']?)(.*?)\1/);
16914
17210
  const srcsetMatch = attrContent.match(/\bsrcset\s*=\s*(["'])(.*?)\1/);
16915
17211
  let src = null;
@@ -16928,59 +17224,155 @@ function deduplicateImages(html) {
16928
17224
  return full;
16929
17225
  });
16930
17226
  }
16931
- function isPreservedImageElement($, el) {
16932
- const tag = (el[0]?.tagName || "").toLowerCase();
17227
+ function hasAttribute2(node, attr) {
17228
+ return node?.attribs?.[attr] !== void 0;
17229
+ }
17230
+ function hasPictureAncestor(node) {
17231
+ let current = node?.parent;
17232
+ while (current) {
17233
+ if (isElementLikeNode(current) && (current.tagName || "").toLowerCase() === "picture") {
17234
+ return true;
17235
+ }
17236
+ current = current.parent;
17237
+ }
17238
+ return false;
17239
+ }
17240
+ function pictureHasPreservedDescendant(node) {
17241
+ if (!node) {
17242
+ return false;
17243
+ }
17244
+ for (const child of getChildNodes(node)) {
17245
+ if (!isElementLikeNode(child)) {
17246
+ continue;
17247
+ }
17248
+ const tag = (child.tagName || "").toLowerCase();
17249
+ if (tag === "img") {
17250
+ return true;
17251
+ }
17252
+ if (tag === "source" && typeof child.attribs?.src === "string" && child.attribs.src.trim() !== "") {
17253
+ return true;
17254
+ }
17255
+ if (tag === "source" && typeof child.attribs?.srcset === "string" && child.attribs.srcset.trim() !== "") {
17256
+ return true;
17257
+ }
17258
+ if (pictureHasPreservedDescendant(child)) {
17259
+ return true;
17260
+ }
17261
+ }
17262
+ return false;
17263
+ }
17264
+ function isPreservedImageElement(node) {
17265
+ const tag = (node?.tagName || "").toLowerCase();
16933
17266
  if (tag === "img") {
16934
17267
  return true;
16935
17268
  }
16936
17269
  if (tag === "picture") {
16937
- const hasImg = el.find("img").length > 0;
16938
- const hasSource = el.find("source[src], source[srcset]").length > 0;
16939
- return hasImg || hasSource;
17270
+ return pictureHasPreservedDescendant(node);
16940
17271
  }
16941
17272
  if (tag === "source") {
16942
- const inPicture = el.parents("picture").length > 0;
16943
- const hasSrc = el.attr("src") != null && el.attr("src").trim() !== "" || el.attr("srcset") != null && el.attr("srcset").trim() !== "";
17273
+ const inPicture = hasPictureAncestor(node);
17274
+ const hasSrc = typeof node?.attribs?.src === "string" && node.attribs.src.trim() !== "" || typeof node?.attribs?.srcset === "string" && node.attribs.srcset.trim() !== "";
16944
17275
  return inPicture && hasSrc;
16945
17276
  }
16946
17277
  return false;
16947
17278
  }
17279
+ function getElementsInReverseDocumentOrder($) {
17280
+ return $.root().find("*").toArray().reverse().filter((node) => node.type === "tag");
17281
+ }
17282
+ function getNodeDepth(node) {
17283
+ let depth = 0;
17284
+ let current = node.parent;
17285
+ while (current) {
17286
+ depth++;
17287
+ current = current.parent;
17288
+ }
17289
+ return depth;
17290
+ }
17291
+ function getElementsByDepthDescending($) {
17292
+ const elements = $.root().find("*").toArray().filter((node) => node.type === "tag");
17293
+ const depths = /* @__PURE__ */ new Map();
17294
+ for (const el of elements) {
17295
+ depths.set(el, getNodeDepth(el));
17296
+ }
17297
+ return elements.sort((a, b) => (depths.get(b) ?? 0) - (depths.get(a) ?? 0));
17298
+ }
16948
17299
  function flattenExtractionTree($) {
16949
- const flatten = (root) => {
16950
- root.find("*").each(function flattenNode() {
16951
- const el = $(this);
16952
- const node = el[0];
16953
- if (!node) {
16954
- return;
16955
- }
16956
- const tag = (node.tagName || "").toLowerCase();
16957
- if (ROOT_TAGS.has(tag) || isBoundaryTag(tag)) {
16958
- return;
16959
- }
16960
- if (isPreservedImageElement($, el)) {
16961
- return;
16962
- }
16963
- if (tag === "a") {
16964
- el.children().each(function flattenAnchorChild() {
16965
- flatten($(this));
16966
- });
16967
- return;
16968
- }
16969
- const hasText = hasDirectText($, el);
16970
- if (hasText) {
16971
- return;
16972
- }
16973
- if (el.children().length === 0) {
16974
- el.remove();
16975
- return;
17300
+ for (const node of getElementsInReverseDocumentOrder($)) {
17301
+ const el = $(node);
17302
+ const tag = (node.tagName || "").toLowerCase();
17303
+ if (ROOT_TAGS.has(tag) || isBoundaryTag(tag) || isPreservedImageElement(node)) {
17304
+ continue;
17305
+ }
17306
+ if (tag === "a" || hasDirectText(node)) {
17307
+ continue;
17308
+ }
17309
+ if (!hasElementChildren(node)) {
17310
+ el.remove();
17311
+ continue;
17312
+ }
17313
+ el.replaceWith(el.contents());
17314
+ }
17315
+ }
17316
+ function hasMarkedAncestor(el, attr) {
17317
+ let current = el[0]?.parent;
17318
+ while (current) {
17319
+ if (!isElementLikeNode(current)) {
17320
+ return false;
17321
+ }
17322
+ if (current.attribs?.[attr] !== void 0) {
17323
+ return true;
17324
+ }
17325
+ current = current.parent;
17326
+ }
17327
+ return false;
17328
+ }
17329
+ function isIndicatorImage(node) {
17330
+ return (node?.tagName || "").toLowerCase() === "img" && (hasAttribute2(node, "alt") || hasAttribute2(node, "src") || hasAttribute2(node, "srcset"));
17331
+ }
17332
+ function isIndicatorPictureSource(node) {
17333
+ return (node?.tagName || "").toLowerCase() === "source" && hasPictureAncestor(node) && (hasAttribute2(node, "src") || hasAttribute2(node, "srcset"));
17334
+ }
17335
+ function isSemanticIndicator(node) {
17336
+ const tag = (node?.tagName || "").toLowerCase();
17337
+ if (tag === "svg") {
17338
+ return true;
17339
+ }
17340
+ return hasAttribute2(node, "aria-label") || hasAttribute2(node, "title") || hasAttribute2(node, "data-icon") || node?.attribs?.role === "img";
17341
+ }
17342
+ function findIndicatorDescendant(root) {
17343
+ if (!root) {
17344
+ return void 0;
17345
+ }
17346
+ let firstImage;
17347
+ let firstSource;
17348
+ let firstSemantic;
17349
+ const visit = (node) => {
17350
+ if (!isElementLikeNode(node)) {
17351
+ return false;
17352
+ }
17353
+ if (isIndicatorImage(node)) {
17354
+ firstImage = node;
17355
+ return true;
17356
+ }
17357
+ if (firstSource === void 0 && isIndicatorPictureSource(node)) {
17358
+ firstSource = node;
17359
+ }
17360
+ if (firstSemantic === void 0 && isSemanticIndicator(node)) {
17361
+ firstSemantic = node;
17362
+ }
17363
+ for (const child of getChildNodes(node)) {
17364
+ if (visit(child)) {
17365
+ return true;
16976
17366
  }
16977
- el.children().each(function flattenChild() {
16978
- flatten($(this));
16979
- });
16980
- el.replaceWith(el.contents());
16981
- });
17367
+ }
17368
+ return false;
16982
17369
  };
16983
- flatten($.root());
17370
+ for (const child of getChildNodes(root)) {
17371
+ if (visit(child)) {
17372
+ return firstImage;
17373
+ }
17374
+ }
17375
+ return firstImage ?? firstSource ?? firstSemantic;
16984
17376
  }
16985
17377
  function serializeForExtraction($, root) {
16986
17378
  const lines = [];
@@ -17049,7 +17441,7 @@ function serializeForExtraction($, root) {
17049
17441
  lines.push(`${" ".repeat(depth)}</${tagName}>`);
17050
17442
  }
17051
17443
  traverse(root, 0);
17052
- return lines.join("\n");
17444
+ return lines.map((l) => l.trim()).filter((l) => l.length > 0).join("");
17053
17445
  }
17054
17446
  function isClickable($, el, context) {
17055
17447
  if (context.hasPreMarked) {
@@ -17141,7 +17533,11 @@ function cleanForExtraction(html) {
17141
17533
  }
17142
17534
  });
17143
17535
  flattenExtractionTree($clean);
17144
- return deduplicateImages(serializeForExtraction($clean, $clean.root()[0]));
17536
+ const root = $clean.root()[0];
17537
+ if (root === void 0) {
17538
+ return "";
17539
+ }
17540
+ return deduplicateImages(serializeForExtraction($clean, root));
17145
17541
  }
17146
17542
  function cleanForAction(html) {
17147
17543
  if (!html.trim()) {
@@ -17167,22 +17563,12 @@ function cleanForAction(html) {
17167
17563
  $(`[${clickableMark}]`).each(function markIndicators() {
17168
17564
  const el = $(this);
17169
17565
  const wrapperAttrs = el.attr() || {};
17170
- if (hasTextDeep(el) || hasActionLabel(wrapperAttrs)) {
17171
- return;
17172
- }
17173
- const imageIndicator = el.find("img[alt], img[src], img[srcset]").first();
17174
- if (imageIndicator.length) {
17175
- imageIndicator.attr(indicatorMark, "1");
17176
- return;
17177
- }
17178
- const pictureSourceIndicator = el.find("picture source[src], picture source[srcset]").first();
17179
- if (pictureSourceIndicator.length) {
17180
- pictureSourceIndicator.attr(indicatorMark, "1");
17566
+ if (hasTextDeepNode(el[0]) || hasActionLabel(wrapperAttrs)) {
17181
17567
  return;
17182
17568
  }
17183
- const semanticIndicator = el.find('[aria-label], [title], [data-icon], [role="img"], svg').first();
17184
- if (semanticIndicator.length) {
17185
- semanticIndicator.attr(indicatorMark, "1");
17569
+ const indicatorNode = findIndicatorDescendant(el[0]);
17570
+ if (indicatorNode !== void 0) {
17571
+ $(indicatorNode).attr(indicatorMark, "1");
17186
17572
  }
17187
17573
  });
17188
17574
  $(`[${clickableMark}]`).each(function removeEmptyClickable() {
@@ -17192,7 +17578,7 @@ function cleanForAction(html) {
17192
17578
  if (NATIVE_INTERACTIVE_TAGS.has(tag) || tag === "a") {
17193
17579
  return;
17194
17580
  }
17195
- if (el.children().length > 0 || hasDirectText($, el)) {
17581
+ if (hasElementChildren(node) || hasDirectText(node)) {
17196
17582
  return;
17197
17583
  }
17198
17584
  const wrapperAttrs = el.attr() || {};
@@ -17218,46 +17604,31 @@ function cleanForAction(html) {
17218
17604
  current = ancestor.parent();
17219
17605
  }
17220
17606
  });
17221
- let changed = true;
17222
- while (changed) {
17223
- changed = false;
17224
- const nodes = [];
17225
- $("*").each(function collectNodes() {
17226
- nodes.push($(this));
17227
- });
17228
- nodes.sort((left, right) => right.parents().length - left.parents().length);
17229
- for (const el of nodes) {
17230
- const node = el[0];
17231
- if (!node) {
17232
- continue;
17233
- }
17234
- const tag = (node.tagName || "").toLowerCase();
17235
- if (ROOT_TAGS.has(tag) || isBoundaryTag(tag)) {
17236
- continue;
17237
- }
17238
- if (el.attr(clickableMark) !== void 0 || el.attr(indicatorMark) !== void 0) {
17239
- continue;
17240
- }
17241
- const insideClickable = el.parents(`[${clickableMark}]`).length > 0;
17242
- const preserveBranch = el.attr(branchMark) !== void 0;
17243
- const hasContent = el.children().length > 0 || hasDirectText($, el);
17244
- if (insideClickable || preserveBranch) {
17245
- if (!hasContent) {
17246
- el.remove();
17247
- } else {
17248
- unwrapActionNode($, el);
17249
- }
17250
- changed = true;
17251
- continue;
17252
- }
17607
+ for (const node of getElementsByDepthDescending($)) {
17608
+ const el = $(node);
17609
+ const tag = (node.tagName || "").toLowerCase();
17610
+ if (ROOT_TAGS.has(tag) || isBoundaryTag(tag)) {
17611
+ continue;
17612
+ }
17613
+ if (el.attr(clickableMark) !== void 0 || el.attr(indicatorMark) !== void 0) {
17614
+ continue;
17615
+ }
17616
+ const insideClickable = hasMarkedAncestor(el, clickableMark);
17617
+ const preserveBranch = el.attr(branchMark) !== void 0;
17618
+ const hasContent = hasElementChildren(node) || hasDirectText(node);
17619
+ if (insideClickable || preserveBranch) {
17253
17620
  if (!hasContent) {
17254
17621
  el.remove();
17255
- changed = true;
17256
- continue;
17622
+ } else {
17623
+ unwrapActionNode($, el);
17257
17624
  }
17258
- unwrapActionNode($, el);
17259
- changed = true;
17625
+ continue;
17626
+ }
17627
+ if (!hasContent) {
17628
+ el.remove();
17629
+ continue;
17260
17630
  }
17631
+ unwrapActionNode($, el);
17261
17632
  }
17262
17633
  $.root().find("*").contents().each(function normalizeActionTextNodes() {
17263
17634
  if (this.type !== "text") {
@@ -17337,21 +17708,7 @@ function cleanForAction(html) {
17337
17708
  OPENSTEER_SPARSE_COUNTER_ATTR
17338
17709
  ]);
17339
17710
  if (clickable) {
17340
- for (const attr of [
17341
- "href",
17342
- "role",
17343
- "type",
17344
- "title",
17345
- "placeholder",
17346
- "value",
17347
- "aria-label",
17348
- "aria-labelledby",
17349
- "aria-describedby",
17350
- "aria-expanded",
17351
- "aria-pressed",
17352
- "aria-selected",
17353
- "aria-haspopup"
17354
- ]) {
17711
+ for (const attr of ["href", "role", "type", "title", "placeholder", "value", "aria-label"]) {
17355
17712
  keep.add(attr);
17356
17713
  }
17357
17714
  }
@@ -17971,9 +18328,9 @@ function renderNode(snapshot, node, nodesById, snapshotsByDocumentRef, snapshotI
17971
18328
  const snapshotAttributes = normalizeNodeAttributes(node.attributes);
17972
18329
  const authoredAttributes = stripInternalSnapshotAttributes(snapshotAttributes);
17973
18330
  const attributes = [...authoredAttributes];
17974
- const subtreeHidden = hasAttribute2(snapshotAttributes, OPENSTEER_HIDDEN_ATTR) || isLikelySubtreeHidden(node);
17975
- const selfHidden = !subtreeHidden && (hasAttribute2(snapshotAttributes, OPENSTEER_SELF_HIDDEN_ATTR) || isLikelySelfHidden(node, nodesById));
17976
- const interactive = !subtreeHidden && !selfHidden && (hasAttribute2(snapshotAttributes, OPENSTEER_INTERACTIVE_ATTR) || isLikelyInteractive(tagName, node, authoredAttributes));
18331
+ const subtreeHidden = hasAttribute3(snapshotAttributes, OPENSTEER_HIDDEN_ATTR) || isLikelySubtreeHidden(node);
18332
+ const selfHidden = !subtreeHidden && (hasAttribute3(snapshotAttributes, OPENSTEER_SELF_HIDDEN_ATTR) || isLikelySelfHidden(node, nodesById));
18333
+ const interactive = !subtreeHidden && !selfHidden && (hasAttribute3(snapshotAttributes, OPENSTEER_INTERACTIVE_ATTR) || isLikelyInteractive(tagName, node, authoredAttributes));
17977
18334
  if (interactive) {
17978
18335
  attributes.push({ name: OPENSTEER_INTERACTIVE_ATTR, value: "1" });
17979
18336
  }
@@ -18291,7 +18648,7 @@ function parseOpacity(value) {
18291
18648
  const parsed = Number.parseFloat(value);
18292
18649
  return Number.isFinite(parsed) ? parsed : Number.NaN;
18293
18650
  }
18294
- function hasAttribute2(attributes, name) {
18651
+ function hasAttribute3(attributes, name) {
18295
18652
  const normalizedName = name.toLowerCase();
18296
18653
  return attributes.some((attribute) => attribute.name.toLowerCase() === normalizedName);
18297
18654
  }
@@ -20252,12 +20609,12 @@ var OpensteerSessionRuntime = class {
20252
20609
  async (timeout) => {
20253
20610
  let descriptor2;
20254
20611
  let data;
20255
- if (input.schema !== void 0) {
20256
- assertValidOpensteerExtractionSchemaRoot(input.schema);
20612
+ if (input.template !== void 0) {
20613
+ assertValidOpensteerExtractionTemplateRoot(input.template);
20257
20614
  const fieldTargets = await timeout.runStep(
20258
20615
  () => compileOpensteerExtractionFieldTargets({
20259
20616
  pageRef,
20260
- schema: input.schema,
20617
+ template: input.template,
20261
20618
  dom: this.requireDom()
20262
20619
  })
20263
20620
  );
@@ -20289,7 +20646,7 @@ var OpensteerSessionRuntime = class {
20289
20646
  () => descriptors.write({
20290
20647
  persist,
20291
20648
  root: payload,
20292
- schemaHash: canonicalJsonString(input.schema),
20649
+ templateHash: canonicalJsonString(input.template),
20293
20650
  sourceUrl: pageInfo.url
20294
20651
  })
20295
20652
  );
@@ -20349,7 +20706,7 @@ var OpensteerSessionRuntime = class {
20349
20706
  artifacts,
20350
20707
  data: {
20351
20708
  ...input.persist === void 0 ? {} : { persist: input.persist },
20352
- ...descriptor?.payload.schemaHash === void 0 ? {} : { schemaHash: descriptor.payload.schemaHash },
20709
+ ...descriptor?.payload.templateHash === void 0 ? {} : { templateHash: descriptor.payload.templateHash },
20353
20710
  data: output.data
20354
20711
  },
20355
20712
  context: buildRuntimeTraceContext({
@@ -24659,142 +25016,6 @@ function screenshotMediaType(format2) {
24659
25016
  return "image/webp";
24660
25017
  }
24661
25018
  }
24662
-
24663
- // ../runtime-core/src/sdk/semantic-dispatch.ts
24664
- async function dispatchSemanticOperation(runtime, operation, input, options = {}) {
24665
- switch (operation) {
24666
- case "session.open":
24667
- return runtime.open(input, options);
24668
- case "page.list":
24669
- return runtime.listPages(
24670
- input,
24671
- options
24672
- );
24673
- case "page.new":
24674
- return runtime.newPage(input, options);
24675
- case "page.activate":
24676
- return runtime.activatePage(
24677
- input,
24678
- options
24679
- );
24680
- case "page.close":
24681
- return runtime.closePage(
24682
- input,
24683
- options
24684
- );
24685
- case "page.goto":
24686
- return runtime.goto(input, options);
24687
- case "page.evaluate":
24688
- return runtime.evaluate(
24689
- input,
24690
- options
24691
- );
24692
- case "page.add-init-script":
24693
- return runtime.addInitScript(
24694
- input,
24695
- options
24696
- );
24697
- case "page.snapshot":
24698
- return runtime.snapshot(
24699
- input,
24700
- options
24701
- );
24702
- case "dom.click":
24703
- return runtime.click(input, options);
24704
- case "dom.hover":
24705
- return runtime.hover(input, options);
24706
- case "dom.input":
24707
- return runtime.input(input, options);
24708
- case "dom.scroll":
24709
- return runtime.scroll(input, options);
24710
- case "dom.extract":
24711
- return runtime.extract(input, options);
24712
- case "network.query":
24713
- return runtime.queryNetwork(
24714
- input,
24715
- options
24716
- );
24717
- case "network.detail":
24718
- return runtime.getNetworkDetail(
24719
- input,
24720
- options
24721
- );
24722
- case "interaction.capture":
24723
- return runtime.captureInteraction(
24724
- input,
24725
- options
24726
- );
24727
- case "interaction.get":
24728
- return runtime.getInteraction(
24729
- input,
24730
- options
24731
- );
24732
- case "interaction.diff":
24733
- return runtime.diffInteraction(
24734
- input,
24735
- options
24736
- );
24737
- case "interaction.replay":
24738
- return runtime.replayInteraction(
24739
- input,
24740
- options
24741
- );
24742
- case "artifact.read":
24743
- return runtime.readArtifact(
24744
- input,
24745
- options
24746
- );
24747
- case "session.cookies":
24748
- return runtime.getCookies(
24749
- input,
24750
- options
24751
- );
24752
- case "session.storage":
24753
- return runtime.getStorageSnapshot(
24754
- input,
24755
- options
24756
- );
24757
- case "session.state":
24758
- return runtime.getBrowserState(
24759
- input,
24760
- options
24761
- );
24762
- case "session.fetch":
24763
- return runtime.fetch(input, options);
24764
- case "scripts.capture":
24765
- return runtime.captureScripts(
24766
- input,
24767
- options
24768
- );
24769
- case "scripts.beautify":
24770
- return runtime.beautifyScript(
24771
- input,
24772
- options
24773
- );
24774
- case "scripts.deobfuscate":
24775
- return runtime.deobfuscateScript(
24776
- input,
24777
- options
24778
- );
24779
- case "scripts.sandbox":
24780
- return runtime.sandboxScript(
24781
- input,
24782
- options
24783
- );
24784
- case "captcha.solve":
24785
- return runtime.solveCaptcha(
24786
- input,
24787
- options
24788
- );
24789
- case "computer.execute":
24790
- return runtime.computerExecute(
24791
- input,
24792
- options
24793
- );
24794
- case "session.close":
24795
- return runtime.close(options);
24796
- }
24797
- }
24798
25019
  var OpensteerSemanticRestError = class extends Error {
24799
25020
  opensteerError;
24800
25021
  statusCode;
@@ -25798,39 +26019,6 @@ var OpensteerRuntime = class extends OpensteerSessionRuntime {
25798
26019
  );
25799
26020
  }
25800
26021
  };
25801
- var OpensteerSessionRuntime2 = class extends OpensteerSessionRuntime {
25802
- constructor(options) {
25803
- const rootPath = options.rootPath ?? path10__default.default.resolve(options.rootDir ?? process.cwd());
25804
- const cleanupRootOnClose = options.cleanupRootOnClose ?? false;
25805
- const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
25806
- assertSupportedEngineOptions({
25807
- engineName,
25808
- ...options.browser === void 0 ? {} : { browser: options.browser },
25809
- ...options.context === void 0 ? {} : { context: options.context }
25810
- });
25811
- super(
25812
- buildSharedRuntimeOptions({
25813
- name: options.name,
25814
- ...options.rootDir === void 0 ? {} : { rootDir: options.rootDir },
25815
- rootPath,
25816
- ...options.environment === void 0 ? {} : { environment: options.environment },
25817
- ...options.browser === void 0 ? {} : { browser: options.browser },
25818
- ...options.launch === void 0 ? {} : { launch: options.launch },
25819
- ...options.context === void 0 ? {} : { context: options.context },
25820
- engineName,
25821
- ...options.engine === void 0 ? {} : { engine: options.engine },
25822
- ...options.engineFactory === void 0 ? {} : { engineFactory: options.engineFactory },
25823
- ...options.policy === void 0 ? {} : { policy: options.policy },
25824
- ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
25825
- ...options.extractionDescriptorStore === void 0 ? {} : { extractionDescriptorStore: options.extractionDescriptorStore },
25826
- cleanupRootOnClose,
25827
- ...options.observability === void 0 ? {} : { observability: options.observability },
25828
- ...options.observationSessionId === void 0 ? {} : { observationSessionId: options.observationSessionId },
25829
- ...options.observationSink === void 0 ? {} : { observationSink: options.observationSink }
25830
- })
25831
- );
25832
- }
25833
- };
25834
26022
  function buildSharedRuntimeOptions(input) {
25835
26023
  const ownership = resolveOwnership(input.browser);
25836
26024
  const engineFactory = input.engineFactory ?? ((factoryOptions) => new OpensteerBrowserManager({
@@ -26098,9 +26286,6 @@ var Opensteer = class {
26098
26286
  await delay3(pollIntervalMs);
26099
26287
  }
26100
26288
  }
26101
- async snapshot(mode = "action") {
26102
- return (await this.runtime.snapshot({ mode })).html;
26103
- }
26104
26289
  async cookies(domain) {
26105
26290
  return new SessionCookieJar(
26106
26291
  await this.runtime.getCookies(domain === void 0 ? {} : { domain })
@@ -26251,7 +26436,6 @@ function delay3(ms) {
26251
26436
  return new Promise((resolve4) => setTimeout(resolve4, ms));
26252
26437
  }
26253
26438
 
26254
- exports.CloudSessionProxy = CloudSessionProxy;
26255
26439
  exports.DEFAULT_OPENSTEER_ENGINE = DEFAULT_OPENSTEER_ENGINE;
26256
26440
  exports.DEFERRED_MATCH_ATTR_KEYS = DEFERRED_MATCH_ATTR_KEYS;
26257
26441
  exports.ElementPathError = ElementPathError;
@@ -26264,8 +26448,6 @@ exports.Opensteer = Opensteer;
26264
26448
  exports.OpensteerAttachAmbiguousError = OpensteerAttachAmbiguousError;
26265
26449
  exports.OpensteerBrowserManager = OpensteerBrowserManager;
26266
26450
  exports.OpensteerCloudClient = OpensteerCloudClient;
26267
- exports.OpensteerRuntime = OpensteerRuntime;
26268
- exports.OpensteerSessionRuntime = OpensteerSessionRuntime2;
26269
26451
  exports.STABLE_PRIMARY_ATTR_KEYS = STABLE_PRIMARY_ATTR_KEYS;
26270
26452
  exports.assertProviderSupportsEngine = assertProviderSupportsEngine;
26271
26453
  exports.buildArrayFieldPathCandidates = buildArrayFieldPathCandidates;
@@ -26285,7 +26467,6 @@ exports.createDomRuntime = createDomRuntime;
26285
26467
  exports.createFilesystemOpensteerWorkspace = createFilesystemOpensteerWorkspace;
26286
26468
  exports.createObservationStore = createObservationStore;
26287
26469
  exports.createOpensteerExtractionDescriptorStore = createOpensteerExtractionDescriptorStore;
26288
- exports.createOpensteerSemanticRuntime = createOpensteerSemanticRuntime;
26289
26470
  exports.defaultFallbackPolicy = defaultFallbackPolicy;
26290
26471
  exports.defaultPolicy = defaultPolicy;
26291
26472
  exports.defaultRetryPolicy = defaultRetryPolicy;
@@ -26293,7 +26474,6 @@ exports.defaultSettlePolicy = defaultSettlePolicy;
26293
26474
  exports.defaultTimeoutPolicy = defaultTimeoutPolicy;
26294
26475
  exports.delayWithSignal = delayWithSignal;
26295
26476
  exports.discoverLocalCdpBrowsers = discoverLocalCdpBrowsers;
26296
- exports.dispatchSemanticOperation = dispatchSemanticOperation;
26297
26477
  exports.hashDomDescriptorPersist = hashDomDescriptorPersist;
26298
26478
  exports.inspectCdpEndpoint = inspectCdpEndpoint;
26299
26479
  exports.isCurrentUrlField = isCurrentUrlField;