@xapp/arachne-web-service 1.33.0 → 1.34.0

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.
@@ -0,0 +1,474 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ServiceExtractor = exports.DEFAULT_MAX_INPUT_TOKENS = exports.EXTRACTOR_VERSION = void 0;
13
+ exports.normalizeText = normalizeText;
14
+ /*! Copyright (c) 2026, XAPP AI */
15
+ const stentor_logger_1 = require("stentor-logger");
16
+ const ServiceTaxonomy_1 = require("../taxonomy/ServiceTaxonomy");
17
+ /**
18
+ * Bumped whenever the prompt, schema or normalizer changes, so stored extractions can be compared by version.
19
+ */
20
+ exports.EXTRACTOR_VERSION = "2026-10-30.1";
21
+ /**
22
+ * Default cap on the page text sent to the LLM, in tokens (estimated at four characters a token).
23
+ */
24
+ exports.DEFAULT_MAX_INPUT_TOKENS = 40000;
25
+ const MAX_SECONDARY_TRADES = 3;
26
+ const CLASSIFY_PAGE_CHARS = 3000;
27
+ const CLASSIFY_MAX_TOKENS = 1024;
28
+ const EXTRACT_MAX_TOKENS = 16384;
29
+ const CHARS_PER_TOKEN = 4;
30
+ const ATTRIBUTE_KINDS = {
31
+ certification: "certifications",
32
+ equipment_type: "equipmentTypes",
33
+ specialty_material: "specialtyMaterials",
34
+ gear: "gear",
35
+ sub_trade: "subTrades",
36
+ };
37
+ const LIST_KINDS = {
38
+ programs: "programs",
39
+ home_warranty_networks: "homeWarrantyNetworks",
40
+ written_reports_certifications: "writtenReportsCertifications",
41
+ languages: "languages",
42
+ };
43
+ const AREA_KINDS = { city: "cities", county: "counties", zip: "zips", radius_miles: "radiusMiles" };
44
+ /**
45
+ * Text as a reader sees it: markdown links, emphasis, escapes and heading underlines removed, quotes and dashes
46
+ * straightened, case and spacing folded.
47
+ */
48
+ function normalizeText(text) {
49
+ return text
50
+ .normalize("NFKC")
51
+ // setext heading underlines, then the backslash escapes turndown adds, e.g. "80123\." for "80123."
52
+ .replace(/^\s*[=-]{3,}\s*$/gm, " ")
53
+ .replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, "$1")
54
+ .replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1")
55
+ .replace(/[*_#`>|]/g, " ")
56
+ .replace(/[‘’]/g, "'")
57
+ .replace(/[“”]/g, '"')
58
+ .replace(/[–—]/g, "-")
59
+ .replace(/\s+/g, " ")
60
+ .trim()
61
+ .toLowerCase();
62
+ }
63
+ function evidenceSchema(urls) {
64
+ return {
65
+ type: "array",
66
+ items: {
67
+ type: "object",
68
+ properties: { url: { type: "string", enum: urls }, snippet: { type: "string" } },
69
+ required: ["url", "snippet"],
70
+ additionalProperties: false,
71
+ },
72
+ };
73
+ }
74
+ function objectSchema(properties) {
75
+ return { type: "object", properties, required: Object.keys(properties), additionalProperties: false };
76
+ }
77
+ function arrayOf(properties) {
78
+ return { type: "array", items: objectSchema(properties) };
79
+ }
80
+ const isString = (v) => typeof v === "string";
81
+ const isNumber = (v) => typeof v === "number" && Number.isFinite(v);
82
+ function isEvidence(v) {
83
+ return Array.isArray(v) && v.every((e) => e && isString(e.url) && isString(e.snippet));
84
+ }
85
+ function isArrayOf(v, check) {
86
+ return Array.isArray(v) && v.every((item) => !!item && typeof item === "object" && check(item));
87
+ }
88
+ function isTradeAnswer(v) {
89
+ return (!!v &&
90
+ isString(v.primary_trade) &&
91
+ isNumber(v.confidence) &&
92
+ Array.isArray(v.secondary_trades) &&
93
+ v.secondary_trades.every(isString) &&
94
+ isEvidence(v.evidence));
95
+ }
96
+ function isExtractionAnswer(v) {
97
+ const evidenced = (i) => isString(i.value) && isEvidence(i.evidence);
98
+ return (!!v &&
99
+ isArrayOf(v.services, (i) => isString(i.slug) && isNumber(i.confidence) && isEvidence(i.evidence)) &&
100
+ isArrayOf(v.unmapped_services, evidenced) &&
101
+ isArrayOf(v.explicit_exclusions, evidenced) &&
102
+ isArrayOf(v.flags, (i) => isString(i.flag) && typeof i.value === "boolean" && isNumber(i.confidence) && isEvidence(i.evidence)) &&
103
+ isArrayOf(v.attributes, (i) => isString(i.kind) && evidenced(i)) &&
104
+ isArrayOf(v.lists, (i) => isString(i.list) && evidenced(i)) &&
105
+ isArrayOf(v.brands_serviced, evidenced) &&
106
+ isArrayOf(v.service_area, (i) => isString(i.kind) && evidenced(i)));
107
+ }
108
+ const clamp = (n) => Math.min(1, Math.max(0, n));
109
+ /**
110
+ * Reads the pages of a business website and returns the services it advertises in Service Taxonomy terms.
111
+ *
112
+ * Two LLM calls at temperature 0: a classifier picks the trades from the start of each page (skipped when the
113
+ * trades are given), then the extractor chooses from those trades' advertised jobs. Each answer must match its
114
+ * JSON schema or it is retried once. Values whose snippet is not on the page they cite are dropped.
115
+ */
116
+ class ServiceExtractor {
117
+ constructor(props) {
118
+ var _a;
119
+ this.provider = props.provider;
120
+ this.taxonomy = (_a = props.taxonomy) !== null && _a !== void 0 ? _a : new ServiceTaxonomy_1.ServiceTaxonomy();
121
+ }
122
+ /**
123
+ * @param pages The pages to read, most important first
124
+ * @returns The extraction, or undefined when no page has text or an LLM answer is unusable after a retry
125
+ */
126
+ extract(pages_1) {
127
+ return __awaiter(this, arguments, void 0, function* (pages, options = {}) {
128
+ var _a, _b;
129
+ const fitted = this.fit(pages.filter((p) => p.markdown.trim()), ((_a = options.maxInputTokens) !== null && _a !== void 0 ? _a : exports.DEFAULT_MAX_INPUT_TOKENS) * CHARS_PER_TOKEN);
130
+ if (fitted.length === 0) {
131
+ (0, stentor_logger_1.log)().info(`No page text to extract services from.`);
132
+ return undefined;
133
+ }
134
+ // Spacing is ignored: the markdown can run words together that the model copies apart
135
+ const squash = (text) => normalizeText(text).replace(/ /g, "");
136
+ const texts = new Map(fitted.map((p) => [p.url, squash(p.markdown)]));
137
+ const rejected = [];
138
+ const onPage = (e) => {
139
+ var _a;
140
+ const snippet = squash(e.snippet);
141
+ return snippet.length >= 3 && !!((_a = texts.get(e.url)) === null || _a === void 0 ? void 0 : _a.includes(snippet));
142
+ };
143
+ const checked = (field, value, evidence) => {
144
+ const kept = evidence.filter(onPage);
145
+ if (kept.length === 0) {
146
+ rejected.push({ field, value, reason: "no_evidence", evidence });
147
+ return undefined;
148
+ }
149
+ return kept;
150
+ };
151
+ const result = {
152
+ taxonomyVersion: this.taxonomy.version,
153
+ extractorVersion: exports.EXTRACTOR_VERSION,
154
+ provider: this.provider.name,
155
+ secondaryTrades: [],
156
+ services: [],
157
+ unmappedServices: [],
158
+ explicitExclusions: [],
159
+ flags: {},
160
+ certifications: [],
161
+ equipmentTypes: [],
162
+ specialtyMaterials: [],
163
+ gear: [],
164
+ subTrades: [],
165
+ programs: [],
166
+ homeWarrantyNetworks: [],
167
+ writtenReportsCertifications: [],
168
+ languages: [],
169
+ brandsServiced: [],
170
+ serviceArea: { cities: [], counties: [], zips: [], radiusMiles: [] },
171
+ pagesRead: fitted.map((p) => p.url),
172
+ rejected,
173
+ extractedAt: new Date().toISOString(),
174
+ };
175
+ let trades = ((_b = options.trades) !== null && _b !== void 0 ? _b : []).filter((t) => this.taxonomy.isTrade(t));
176
+ if (trades.length > 0) {
177
+ result.primaryTrade = { value: trades[0], confidence: 1, evidence: [] };
178
+ result.secondaryTrades = trades.slice(1).map((value) => ({ value, confidence: 1, evidence: [] }));
179
+ }
180
+ else {
181
+ const answer = yield this.ask(this.classifyPrompt(fitted), this.classifySchema(fitted), CLASSIFY_MAX_TOKENS, isTradeAnswer, "services_trades");
182
+ if (!answer) {
183
+ return undefined;
184
+ }
185
+ if (!this.taxonomy.isTrade(answer.primary_trade)) {
186
+ (0, stentor_logger_1.log)().info(`Not a home-services business, no trade found.`);
187
+ return result;
188
+ }
189
+ const evidence = answer.evidence.filter(onPage);
190
+ const secondary = [...new Set(answer.secondary_trades)]
191
+ .filter((t) => t !== answer.primary_trade && this.taxonomy.isTrade(t))
192
+ .slice(0, MAX_SECONDARY_TRADES);
193
+ result.primaryTrade = { value: answer.primary_trade, confidence: clamp(answer.confidence), evidence };
194
+ result.secondaryTrades = secondary.map((value) => ({
195
+ value,
196
+ confidence: clamp(answer.confidence),
197
+ evidence: [],
198
+ }));
199
+ trades = [answer.primary_trade, ...secondary];
200
+ }
201
+ const catalog = this.catalog(trades);
202
+ const answer = yield this.ask(this.extractPrompt(fitted, catalog), this.extractSchema(fitted, catalog), EXTRACT_MAX_TOKENS, isExtractionAnswer, "services_extract");
203
+ if (!answer) {
204
+ return undefined;
205
+ }
206
+ this.normalize(answer, result, checked);
207
+ (0, stentor_logger_1.log)().info(`Extracted ${result.services.length} services for ${trades.join(", ")} from ${fitted.length} pages, rejected ${rejected.length} values`);
208
+ return result;
209
+ });
210
+ }
211
+ normalize(answer, result, checked) {
212
+ const definitions = serviceLists(this.taxonomy);
213
+ for (const service of answer.services) {
214
+ const family = this.taxonomy.isFamily(service.slug) ? service.slug : undefined;
215
+ const slug = family !== null && family !== void 0 ? family : this.taxonomy.resolve(service.slug);
216
+ const job = family
217
+ ? { slug: family, trade: family.split(".")[0], family, homeowner_only: false }
218
+ : slug
219
+ ? this.taxonomy.job(slug)
220
+ : undefined;
221
+ if (!job) {
222
+ const evidence = checked("unmappedServices", service.slug, service.evidence);
223
+ if (evidence) {
224
+ result.unmappedServices.push({ value: service.slug, evidence });
225
+ }
226
+ continue;
227
+ }
228
+ if (job.homeowner_only) {
229
+ result.rejected.push({ field: "services", value: service.slug, reason: "homeowner_only" });
230
+ continue;
231
+ }
232
+ const evidence = checked("services", service.slug, service.evidence);
233
+ if (!evidence) {
234
+ continue;
235
+ }
236
+ const existing = result.services.find((s) => s.slug === job.slug);
237
+ if (existing) {
238
+ existing.confidence = Math.max(existing.confidence, clamp(service.confidence));
239
+ existing.evidence.push(...evidence);
240
+ }
241
+ else {
242
+ result.services.push(Object.assign(Object.assign({ slug: job.slug, trade: job.trade }, (job.family ? { family: job.family } : {})), { confidence: clamp(service.confidence), evidence }));
243
+ }
244
+ }
245
+ const push = (field, target, item) => {
246
+ const evidence = checked(field, item.value, item.evidence);
247
+ if (evidence) {
248
+ target.push({ value: item.value, evidence });
249
+ }
250
+ };
251
+ answer.unmapped_services.forEach((item) => push("unmappedServices", result.unmappedServices, item));
252
+ answer.explicit_exclusions.forEach((item) => push("explicitExclusions", result.explicitExclusions, item));
253
+ answer.brands_serviced.forEach((item) => push("brandsServiced", result.brandsServiced, item));
254
+ for (const flag of answer.flags) {
255
+ if (!definitions.flags.includes(flag.flag)) {
256
+ result.rejected.push({ field: "flags", value: flag.flag, reason: "not_in_taxonomy" });
257
+ continue;
258
+ }
259
+ const evidence = checked("flags", flag.flag, flag.evidence);
260
+ if (evidence) {
261
+ result.flags[flag.flag] = { value: flag.value, confidence: clamp(flag.confidence), evidence };
262
+ }
263
+ }
264
+ for (const attribute of answer.attributes) {
265
+ const field = ATTRIBUTE_KINDS[attribute.kind];
266
+ if (!field ||
267
+ !definitions.attributes[attribute.kind].includes(attribute.value)) {
268
+ result.rejected.push({
269
+ field: field !== null && field !== void 0 ? field : "attributes",
270
+ value: attribute.value,
271
+ reason: "not_in_taxonomy",
272
+ });
273
+ continue;
274
+ }
275
+ push(field, result[field], attribute);
276
+ }
277
+ for (const item of answer.lists) {
278
+ const field = LIST_KINDS[item.list];
279
+ if (!field) {
280
+ result.rejected.push({ field: "lists", value: item.value, reason: "not_in_taxonomy" });
281
+ continue;
282
+ }
283
+ push(field, result[field], item);
284
+ }
285
+ for (const item of answer.service_area) {
286
+ const field = AREA_KINDS[item.kind];
287
+ if (!field) {
288
+ result.rejected.push({ field: "serviceArea", value: item.value, reason: "not_in_taxonomy" });
289
+ continue;
290
+ }
291
+ push(`serviceArea.${field}`, result.serviceArea[field], item);
292
+ }
293
+ }
294
+ /**
295
+ * Keeps every page, trimming the longest ones until the total fits the budget.
296
+ */
297
+ fit(pages, budgetChars) {
298
+ const lengths = pages.map((p) => p.markdown.length).sort((a, b) => a - b);
299
+ if (lengths.reduce((sum, n) => sum + n, 0) <= budgetChars) {
300
+ return pages;
301
+ }
302
+ // Pages shorter than an even share keep their text and hand what they leave over to the longer ones
303
+ let remaining = budgetChars;
304
+ let cap = 0;
305
+ for (let i = 0; i < lengths.length; i++) {
306
+ cap = Math.floor(remaining / (lengths.length - i));
307
+ if (lengths[i] > cap) {
308
+ break;
309
+ }
310
+ remaining -= lengths[i];
311
+ }
312
+ return pages.map((p) => (p.markdown.length > cap ? Object.assign(Object.assign({}, p), { markdown: p.markdown.slice(0, cap) }) : p));
313
+ }
314
+ pagesBlock(pages, chars) {
315
+ return pages
316
+ .map((p) => `=== PAGE ${p.url} (${p.kind}) ===\n${chars ? p.markdown.slice(0, chars) : p.markdown}`)
317
+ .join("\n\n");
318
+ }
319
+ classifyPrompt(pages) {
320
+ const trades = serviceLists(this.taxonomy).trades.join(", ");
321
+ return `You read the start of each page of a business website and decide which home-service trades the business works in.
322
+
323
+ Trades: ${trades}
324
+
325
+ Rules:
326
+ - primary_trade is the trade most of its services belong to, or "none" when it is not a home-services business (e.g. a spa, a retailer, a software company).
327
+ - secondary_trades are other trades it clearly advertises, at most ${MAX_SECONDARY_TRADES}.
328
+ - evidence is one or two snippets copied exactly from the pages that show the primary trade.
329
+
330
+ ${this.pagesBlock(pages, CLASSIFY_PAGE_CHARS)}`;
331
+ }
332
+ classifySchema(pages) {
333
+ const trades = serviceLists(this.taxonomy).trades;
334
+ return objectSchema({
335
+ primary_trade: { type: "string", enum: [...trades, "none"] },
336
+ confidence: { type: "number" },
337
+ secondary_trades: { type: "array", items: { type: "string", enum: trades } },
338
+ evidence: evidenceSchema(pages.map((p) => p.url)),
339
+ });
340
+ }
341
+ /**
342
+ * The slugs the extractor may choose for the trades: each family, for a service advertised in general terms,
343
+ * followed by its advertised jobs, then the jobs that sit directly under a trade.
344
+ */
345
+ catalog(trades) {
346
+ var _a, _b;
347
+ const jobs = this.taxonomy.extractableJobs(trades);
348
+ const entries = [];
349
+ for (const trade of this.taxonomy.definition.trades.filter((t) => trades.includes(t.slug))) {
350
+ for (const family of (_a = trade.families) !== null && _a !== void 0 ? _a : []) {
351
+ entries.push({ slug: family.slug, general: true, terms: (_b = family.website_terms) !== null && _b !== void 0 ? _b : [] });
352
+ jobs.filter((j) => j.family === family.slug).forEach((j) => { var _a; return entries.push({ slug: j.slug, terms: (_a = j.synonyms) !== null && _a !== void 0 ? _a : [] }); });
353
+ }
354
+ jobs.filter((j) => j.trade === trade.slug && !j.family).forEach((j) => { var _a; return entries.push({ slug: j.slug, terms: (_a = j.synonyms) !== null && _a !== void 0 ? _a : [] }); });
355
+ }
356
+ return entries;
357
+ }
358
+ extractPrompt(pages, catalog) {
359
+ const lists = serviceLists(this.taxonomy);
360
+ const catalogText = catalog
361
+ .map((e) => `- ${e.slug}${e.general ? " (general)" : ""}${e.terms.length ? `: ${e.terms.join("; ")}` : ""}`)
362
+ .join("\n");
363
+ const flags = this.taxonomy.definition.capability_flags
364
+ .map((f) => `- ${f.slug}: ${f.definition}`)
365
+ .join("\n");
366
+ const listDefs = this.taxonomy.definition.capability_lists
367
+ .map((l) => `- ${l.slug}: ${l.definition}`)
368
+ .join("\n");
369
+ const attributes = Object.entries(lists.attributes)
370
+ .map(([kind, values]) => `- ${kind}: ${values.join(", ")}`)
371
+ .join("\n");
372
+ return `You read the pages of a home-services business website and list what the business advertises, using the catalog below.
373
+
374
+ Every value needs evidence: the URL of the page it is on and a snippet copied exactly, word for word, from that page (5 to 25 words). No evidence, no value. Do not infer, guess or generalise.
375
+
376
+ - services: catalog slugs for jobs the business says it performs. Pick the most specific slug the page supports; a slug marked (general) is for a service the site advertises only in general terms, e.g. "AC repair". Anything the business offers that has no catalog slug goes in unmapped_services, worded as the site words it.
377
+ - explicit_exclusions: anything the site says it does not do.
378
+ - flags: include a flag only when the pages state it. value is false only when the site says the opposite. Leave out flags the pages do not mention.
379
+ - attributes: certifications, equipment types, specialty materials, gear and sub-trade specialisms from the lists below that the pages name.
380
+ - lists: financing programs, home warranty networks, written reports and languages the pages name, as free text.
381
+ - brands_serviced: equipment or product brands the business installs or services.
382
+ - service_area: cities, counties, ZIP codes, or a radius in miles that the business says it serves.
383
+
384
+ Catalog (slug: words customers and websites use):
385
+ ${catalogText}
386
+
387
+ Flags:
388
+ ${flags}
389
+
390
+ Attributes:
391
+ ${attributes}
392
+
393
+ Lists:
394
+ ${listDefs}
395
+
396
+ ${this.pagesBlock(pages)}`;
397
+ }
398
+ extractSchema(pages, catalog) {
399
+ const lists = serviceLists(this.taxonomy);
400
+ const evidence = evidenceSchema(pages.map((p) => p.url));
401
+ const valued = (extra = {}) => arrayOf(Object.assign(Object.assign({}, extra), { value: { type: "string" }, evidence }));
402
+ const attributeValues = [...new Set(Object.values(lists.attributes).flat())];
403
+ return objectSchema({
404
+ services: arrayOf({
405
+ slug: { type: "string", enum: catalog.map((e) => e.slug) },
406
+ confidence: { type: "number" },
407
+ evidence,
408
+ }),
409
+ unmapped_services: valued(),
410
+ explicit_exclusions: valued(),
411
+ flags: arrayOf({
412
+ flag: { type: "string", enum: lists.flags },
413
+ value: { type: "boolean" },
414
+ confidence: { type: "number" },
415
+ evidence,
416
+ }),
417
+ attributes: arrayOf({
418
+ kind: { type: "string", enum: Object.keys(ATTRIBUTE_KINDS) },
419
+ value: { type: "string", enum: attributeValues },
420
+ evidence,
421
+ }),
422
+ lists: valued({ list: { type: "string", enum: Object.keys(LIST_KINDS) } }),
423
+ brands_serviced: valued(),
424
+ service_area: valued({ kind: { type: "string", enum: Object.keys(AREA_KINDS) } }),
425
+ });
426
+ }
427
+ /**
428
+ * Calls the LLM and checks the answer's shape, retrying once.
429
+ */
430
+ ask(prompt, jsonSchema, maxTokens, check, label) {
431
+ return __awaiter(this, void 0, void 0, function* () {
432
+ for (let attempt = 1; attempt <= 2; attempt++) {
433
+ const text = yield this.provider.complete({
434
+ prompt,
435
+ jsonSchema,
436
+ maxTokens,
437
+ temperature: 0,
438
+ label: `${label}_${attempt}`,
439
+ });
440
+ let parsed;
441
+ try {
442
+ parsed = text === undefined ? undefined : JSON.parse(text);
443
+ }
444
+ catch (_a) {
445
+ parsed = undefined;
446
+ }
447
+ if (check(parsed)) {
448
+ return parsed;
449
+ }
450
+ (0, stentor_logger_1.log)().warn(`${label}: answer ${text === undefined ? "missing" : "does not match the schema"} on attempt ${attempt}`);
451
+ }
452
+ return undefined;
453
+ });
454
+ }
455
+ }
456
+ exports.ServiceExtractor = ServiceExtractor;
457
+ /**
458
+ * The enumerations the prompts and schemas offer.
459
+ */
460
+ function serviceLists(taxonomy) {
461
+ const d = taxonomy.definition;
462
+ return {
463
+ trades: d.trades.map((t) => t.slug),
464
+ flags: d.capability_flags.map((f) => f.slug),
465
+ attributes: {
466
+ certification: d.certifications,
467
+ equipment_type: d.equipment_types,
468
+ specialty_material: d.specialty_materials,
469
+ gear: d.gear,
470
+ sub_trade: d.sub_trades,
471
+ },
472
+ };
473
+ }
474
+ //# sourceMappingURL=ServiceExtractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceExtractor.js","sourceRoot":"","sources":["../../src/services/ServiceExtractor.ts"],"names":[],"mappings":";;;;;;;;;;;;AAsNA,sCAcC;AApOD,kCAAkC;AAClC,mDAAqC;AAGrC,iEAA8D;AAG9D;;GAEG;AACU,QAAA,iBAAiB,GAAG,cAAc,CAAC;AAEhD;;GAEG;AACU,QAAA,wBAAwB,GAAG,KAAK,CAAC;AAE9C,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC,MAAM,eAAe,GAAG,CAAC,CAAC;AAwI1B,MAAM,eAAe,GAAG;IACpB,aAAa,EAAE,gBAAgB;IAC/B,cAAc,EAAE,gBAAgB;IAChC,kBAAkB,EAAE,oBAAoB;IACxC,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,WAAW;CAChB,CAAC;AAEX,MAAM,UAAU,GAAG;IACf,QAAQ,EAAE,UAAU;IACpB,sBAAsB,EAAE,sBAAsB;IAC9C,8BAA8B,EAAE,8BAA8B;IAC9D,SAAS,EAAE,WAAW;CAChB,CAAC;AAEX,MAAM,UAAU,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAW,CAAC;AAkC7G;;;GAGG;AACH,SAAgB,aAAa,CAAC,IAAY;IACtC,OAAO,IAAI;SACN,SAAS,CAAC,MAAM,CAAC;QAClB,mGAAmG;SAClG,OAAO,CAAC,oBAAoB,EAAE,GAAG,CAAC;SAClC,OAAO,CAAC,8BAA8B,EAAE,IAAI,CAAC;SAC7C,OAAO,CAAC,0BAA0B,EAAE,IAAI,CAAC;SACzC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC;SACzB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;AACvB,CAAC;AAED,SAAS,cAAc,CAAC,IAAc;IAClC,OAAO;QACH,IAAI,EAAE,OAAO;QACb,KAAK,EAAE;YACH,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YAChF,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC;YAC5B,oBAAoB,EAAE,KAAK;SAC9B;KACJ,CAAC;AACN,CAAC;AAED,SAAS,YAAY,CAAC,UAAkC;IACpD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC;AAC1G,CAAC;AAED,SAAS,OAAO,CAAC,UAAkC;IAC/C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;AAEpE,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAE1F,SAAS,UAAU,CAAC,CAAU;IAC1B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED,SAAS,SAAS,CAAC,CAAU,EAAE,KAA6B;IACxD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACpG,CAAC;AAED,SAAS,aAAa,CAAC,CAAM;IACzB,OAAO,CACH,CAAC,CAAC,CAAC;QACH,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC;QACzB,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;QACtB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC;QACjC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC;QAClC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CACzB,CAAC;AACN,CAAC;AAED,SAAS,kBAAkB,CAAC,CAAM;IAC9B,MAAM,SAAS,GAAG,CAAC,CAAM,EAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACnF,OAAO,CACH,CAAC,CAAC,CAAC;QACH,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAClG,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,SAAS,CAAC;QACzC,SAAS,CAAC,CAAC,CAAC,mBAAmB,EAAE,SAAS,CAAC;QAC3C,SAAS,CACL,CAAC,CAAC,KAAK,EACP,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAC9G;QACD,SAAS,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;QAChE,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3D,SAAS,CAAC,CAAC,CAAC,eAAe,EAAE,SAAS,CAAC;QACvC,SAAS,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,CACrE,CAAC;AACN,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAEjE;;;;;;GAMG;AACH,MAAa,gBAAgB;IAKzB,YAAY,KAA4D;;QACpE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,MAAA,KAAK,CAAC,QAAQ,mCAAI,IAAI,iCAAe,EAAE,CAAC;IAC5D,CAAC;IAED;;;OAGG;IACG,OAAO;6DACT,KAAwB,EACxB,UAAsC,EAAE;;YAExC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CACnB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EACtC,CAAC,MAAA,OAAO,CAAC,cAAc,mCAAI,gCAAwB,CAAC,GAAG,eAAe,CACzE,CAAC;YACF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,IAAA,oBAAG,GAAE,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;gBACrD,OAAO,SAAS,CAAC;YACrB,CAAC;YAED,sFAAsF;YACtF,MAAM,MAAM,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC/E,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YACtE,MAAM,QAAQ,GAAoB,EAAE,CAAC;YACrC,MAAM,MAAM,GAAG,CAAC,CAAkB,EAAW,EAAE;;gBAC3C,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;gBAClC,OAAO,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA,MAAA,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,0CAAE,QAAQ,CAAC,OAAO,CAAC,CAAA,CAAC;YACxE,CAAC,CAAC;YACF,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,KAAa,EAAE,QAA2B,EAAiC,EAAE;gBACzG,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACrC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;oBACjE,OAAO,SAAS,CAAC;gBACrB,CAAC;gBACD,OAAO,IAAI,CAAC;YAChB,CAAC,CAAC;YAEF,MAAM,MAAM,GAAsB;gBAC9B,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO;gBACtC,gBAAgB,EAAE,yBAAiB;gBACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;gBAC5B,eAAe,EAAE,EAAE;gBACnB,QAAQ,EAAE,EAAE;gBACZ,gBAAgB,EAAE,EAAE;gBACpB,kBAAkB,EAAE,EAAE;gBACtB,KAAK,EAAE,EAAE;gBACT,cAAc,EAAE,EAAE;gBAClB,cAAc,EAAE,EAAE;gBAClB,kBAAkB,EAAE,EAAE;gBACtB,IAAI,EAAE,EAAE;gBACR,SAAS,EAAE,EAAE;gBACb,QAAQ,EAAE,EAAE;gBACZ,oBAAoB,EAAE,EAAE;gBACxB,4BAA4B,EAAE,EAAE;gBAChC,SAAS,EAAE,EAAE;gBACb,cAAc,EAAE,EAAE;gBAClB,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;gBACpE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;gBACnC,QAAQ;gBACR,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACxC,CAAC;YAEF,IAAI,MAAM,GAAG,CAAC,MAAA,OAAO,CAAC,MAAM,mCAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5E,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,MAAM,CAAC,YAAY,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;gBACxE,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YACtG,CAAC;iBAAM,CAAC;gBACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CACzB,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAC3B,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAC3B,mBAAmB,EACnB,aAAa,EACb,iBAAiB,CACpB,CAAC;gBACF,IAAI,CAAC,MAAM,EAAE,CAAC;oBACV,OAAO,SAAS,CAAC;gBACrB,CAAC;gBACD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;oBAC/C,IAAA,oBAAG,GAAE,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;oBAC5D,OAAO,MAAM,CAAC;gBAClB,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAChD,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;qBAClD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,aAAa,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;qBACrE,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;gBACpC,MAAM,CAAC,YAAY,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;gBACtG,MAAM,CAAC,eAAe,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBAC/C,KAAK;oBACL,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC;oBACpC,QAAQ,EAAE,EAAE;iBACf,CAAC,CAAC,CAAC;gBACJ,MAAM,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,SAAS,CAAC,CAAC;YAClD,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CACzB,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,CACrB,CAAC;YACF,IAAI,CAAC,MAAM,EAAE,CAAC;gBACV,OAAO,SAAS,CAAC;YACrB,CAAC;YAED,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YAExC,IAAA,oBAAG,GAAE,CAAC,IAAI,CACN,aAAa,MAAM,CAAC,QAAQ,CAAC,MAAM,iBAAiB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SACjE,MAAM,CAAC,MACX,oBAAoB,QAAQ,CAAC,MAAM,SAAS,CAC/C,CAAC;YAEF,OAAO,MAAM,CAAC;QAClB,CAAC;KAAA;IAEO,SAAS,CACb,MAAwB,EACxB,MAAyB,EACzB,OAAqG;QAErG,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEhD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YAC/E,MAAM,IAAI,GAAG,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC3D,MAAM,GAAG,GAAG,MAAM;gBACd,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE;gBAC9E,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;oBACzB,CAAC,CAAC,SAAS,CAAC;YAChB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACP,MAAM,QAAQ,GAAG,OAAO,CAAC,kBAAkB,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC7E,IAAI,QAAQ,EAAE,CAAC;oBACX,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACpE,CAAC;gBACD,SAAS;YACb,CAAC;YACD,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;gBACrB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;gBAC3F,SAAS;YACb,CAAC;YACD,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;YACrE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACZ,SAAS;YACb,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC;YAClE,IAAI,QAAQ,EAAE,CAAC;gBACX,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;gBAC/E,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACJ,MAAM,CAAC,QAAQ,CAAC,IAAI,+BAChB,IAAI,EAAE,GAAG,CAAC,IAAI,EACd,KAAK,EAAE,GAAG,CAAC,KAAK,IACb,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC7C,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EACrC,QAAQ,IACV,CAAC;YACP,CAAC;QACL,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,MAAwB,EAAE,IAAkB,EAAQ,EAAE;YAC/E,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC3D,IAAI,QAAQ,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YACjD,CAAC;QACL,CAAC,CAAC;QAEF,MAAM,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC;QACpG,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1G,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC,CAAC;QAE9F,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;gBACtF,SAAS;YACb,CAAC;YACD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5D,IAAI,QAAQ,EAAE,CAAC;gBACX,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;YAClG,CAAC;QACL,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,eAAe,CAAC,SAAS,CAAC,IAAoC,CAAC,CAAC;YAC9E,IACI,CAAC,KAAK;gBACN,CAAC,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,IAAoC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,EACnG,CAAC;gBACC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACjB,KAAK,EAAE,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,YAAY;oBAC5B,KAAK,EAAE,SAAS,CAAC,KAAK;oBACtB,MAAM,EAAE,iBAAiB;iBAC5B,CAAC,CAAC;gBACH,SAAS;YACb,CAAC;YACD,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC;QAC1C,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAA+B,CAAC,CAAC;YAC/D,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;gBACvF,SAAS;YACb,CAAC;YACD,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;QACrC,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAA+B,CAAC,CAAC;YAC/D,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;gBAC7F,SAAS;YACb,CAAC;YACD,IAAI,CAAC,eAAe,KAAK,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;QAClE,CAAC;IACL,CAAC;IAED;;OAEG;IACK,GAAG,CAAC,KAAwB,EAAE,WAAmB;QACrD,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1E,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC;YACxD,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,oGAAoG;QACpG,IAAI,SAAS,GAAG,WAAW,CAAC;QAC5B,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACnD,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC;gBACnB,MAAM;YACV,CAAC;YACD,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,iCAAM,CAAC,KAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1G,CAAC;IAEO,UAAU,CAAC,KAAwB,EAAE,KAAc;QACvD,OAAO,KAAK;aACP,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;aACnG,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;IAEO,cAAc,CAAC,KAAwB;QAC3C,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,OAAO;;UAEL,MAAM;;;;qEAIqD,oBAAoB;;;EAGvF,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,mBAAmB,CAAC,EAAE,CAAC;IAC5C,CAAC;IAEO,cAAc,CAAC,KAAwB;QAC3C,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;QAClD,OAAO,YAAY,CAAC;YAChB,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE;YAC5D,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC9B,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;YAC5E,QAAQ,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;SACpD,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACK,OAAO,CAAC,MAAgB;;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QACnD,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACzF,KAAK,MAAM,MAAM,IAAI,MAAA,KAAK,CAAC,QAAQ,mCAAI,EAAE,EAAE,CAAC;gBACxC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAA,MAAM,CAAC,aAAa,mCAAI,EAAE,EAAE,CAAC,CAAC;gBACtF,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,WAAC,OAAA,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,MAAA,CAAC,CAAC,QAAQ,mCAAI,EAAE,EAAE,CAAC,CAAA,EAAA,CAAC,CAAC;YACzH,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,WAAC,OAAA,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,MAAA,CAAC,CAAC,QAAQ,mCAAI,EAAE,EAAE,CAAC,CAAA,EAAA,CAAC,CAAC;QACpI,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAEO,aAAa,CAAC,KAAwB,EAAE,OAAuB;QACnE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,WAAW,GAAG,OAAO;aACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;aAC3G,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,gBAAgB;aAClD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;aAC1C,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,gBAAgB;aACrD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;aAC1C,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC;aAC9C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;aAC1D,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhB,OAAO;;;;;;;;;;;;;EAab,WAAW;;;EAGX,KAAK;;;EAGL,UAAU;;;EAGV,QAAQ;;EAER,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;IACvB,CAAC;IAEO,aAAa,CAAC,KAAwB,EAAE,OAAuB;QACnE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,CAAC,QAAgC,EAAE,EAAU,EAAE,CAC1D,OAAO,iCAAM,KAAK,KAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,QAAQ,IAAG,CAAC;QAC/D,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAE7E,OAAO,YAAY,CAAC;YAChB,QAAQ,EAAE,OAAO,CAAC;gBACd,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;gBAC1D,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC9B,QAAQ;aACX,CAAC;YACF,iBAAiB,EAAE,MAAM,EAAE;YAC3B,mBAAmB,EAAE,MAAM,EAAE;YAC7B,KAAK,EAAE,OAAO,CAAC;gBACX,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE;gBAC3C,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBAC1B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC9B,QAAQ;aACX,CAAC;YACF,UAAU,EAAE,OAAO,CAAC;gBAChB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE;gBAC5D,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE;gBAChD,QAAQ;aACX,CAAC;YACF,KAAK,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;YAC1E,eAAe,EAAE,MAAM,EAAE;YACzB,YAAY,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;SACpF,CAAC,CAAC;IACP,CAAC;IAED;;OAEG;IACW,GAAG,CACb,MAAc,EACd,UAAkB,EAClB,SAAiB,EACjB,KAA6B,EAC7B,KAAa;;YAEb,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;gBAC5C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBACtC,MAAM;oBACN,UAAU;oBACV,SAAS;oBACT,WAAW,EAAE,CAAC;oBACd,KAAK,EAAE,GAAG,KAAK,IAAI,OAAO,EAAE;iBAC/B,CAAC,CAAC;gBACH,IAAI,MAAe,CAAC;gBACpB,IAAI,CAAC;oBACD,MAAM,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/D,CAAC;gBAAC,WAAM,CAAC;oBACL,MAAM,GAAG,SAAS,CAAC;gBACvB,CAAC;gBACD,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;oBAChB,OAAO,MAAM,CAAC;gBAClB,CAAC;gBACD,IAAA,oBAAG,GAAE,CAAC,IAAI,CACN,GAAG,KAAK,YAAY,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,2BAA2B,eAAe,OAAO,EAAE,CAC3G,CAAC;YACN,CAAC;YACD,OAAO,SAAS,CAAC;QACrB,CAAC;KAAA;CACJ;AAjZD,4CAiZC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,QAAyB;IAK3C,MAAM,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC;IAC9B,OAAO;QACH,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACnC,KAAK,EAAE,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5C,UAAU,EAAE;YACR,aAAa,EAAE,CAAC,CAAC,cAAc;YAC/B,cAAc,EAAE,CAAC,CAAC,eAAe;YACjC,kBAAkB,EAAE,CAAC,CAAC,mBAAmB;YACzC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,SAAS,EAAE,CAAC,CAAC,UAAU;SAC1B;KACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { SubpageTab } from "../utils/subpageDetection";
2
+ import { ServicePage } from "./selectServicePages";
3
+ import { ServicePageText } from "./ServiceExtractor";
4
+ export interface ReadServicePagesProps {
5
+ /**
6
+ * Opens a new tab with the crawler's page setup.
7
+ */
8
+ openTab: () => Promise<SubpageTab>;
9
+ homepageUrl: string;
10
+ /**
11
+ * Pages to read, in order. The homepage is not visited again.
12
+ */
13
+ targets: ServicePage[];
14
+ /**
15
+ * Converts a page's HTML to the markdown sent to the LLM.
16
+ */
17
+ toMarkdown: (html: string) => string;
18
+ /**
19
+ * Budget for each page.
20
+ */
21
+ pageTimeoutMs: number;
22
+ /**
23
+ * No page is started after this time (epoch ms).
24
+ */
25
+ deadline: number;
26
+ /**
27
+ * HTML of pages already loaded during the crawl, by URL. These are not visited again.
28
+ */
29
+ loaded?: Map<string, string>;
30
+ }
31
+ /**
32
+ * Loads each target on its own tab, in order, and returns its text.
33
+ *
34
+ * A page that errors, times out or redirects off-site is skipped. Pages are not started once the deadline is
35
+ * near.
36
+ */
37
+ export declare function readServicePages(props: ReadServicePagesProps): Promise<ServicePageText[]>;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.readServicePages = readServicePages;
13
+ /*! Copyright (c) 2026, XAPP AI */
14
+ const arachne_utils_1 = require("@xapp/arachne-utils");
15
+ const stentor_logger_1 = require("stentor-logger");
16
+ const subpageDetection_1 = require("../utils/subpageDetection");
17
+ /**
18
+ * Loads each target on its own tab, in order, and returns its text.
19
+ *
20
+ * A page that errors, times out or redirects off-site is skipped. Pages are not started once the deadline is
21
+ * near.
22
+ */
23
+ function readServicePages(props) {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ const { openTab, homepageUrl, targets, toMarkdown, pageTimeoutMs, deadline, loaded } = props;
26
+ const pages = [];
27
+ for (const [index, target] of targets.entries()) {
28
+ if (target.kind === "homepage") {
29
+ continue;
30
+ }
31
+ const cached = loaded === null || loaded === void 0 ? void 0 : loaded.get(target.url);
32
+ if (cached !== undefined) {
33
+ pages.push({ url: target.url, kind: target.kind, markdown: toMarkdown(cached) });
34
+ continue;
35
+ }
36
+ const remaining = deadline - Date.now();
37
+ if (remaining < subpageDetection_1.MIN_SUBPAGE_BUDGET_MS) {
38
+ (0, stentor_logger_1.log)().info(`Service pages: budget exhausted, not reading ${targets.length - index} more page(s).`);
39
+ break;
40
+ }
41
+ const budget = Math.min(pageTimeoutMs, remaining);
42
+ // A fresh tab per page, so a navigation that outlives its budget is cancelled by closing the tab
43
+ const tab = (0, subpageDetection_1.createLazyTab)(openTab);
44
+ try {
45
+ const html = yield (0, arachne_utils_1.promiseWithTimeout)(budget, () => __awaiter(this, void 0, void 0, function* () { return (0, subpageDetection_1.loadSameSitePage)(yield tab.get(), target.url, homepageUrl, budget); }), `Service page ${target.url} exceeded its budget of ${budget}ms`);
46
+ pages.push({ url: target.url, kind: target.kind, markdown: toMarkdown(html) });
47
+ }
48
+ catch (e) {
49
+ (0, stentor_logger_1.log)().warn(`Service pages: skipping ${target.url}: ${e instanceof Error ? e.message : e}`);
50
+ }
51
+ finally {
52
+ yield tab.close();
53
+ }
54
+ }
55
+ return pages;
56
+ });
57
+ }
58
+ //# sourceMappingURL=readServicePages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readServicePages.js","sourceRoot":"","sources":["../../src/services/readServicePages.ts"],"names":[],"mappings":";;;;;;;;;;;AA0CA,4CAuCC;AAjFD,kCAAkC;AAClC,uDAAyD;AACzD,mDAAqC;AAErC,gEAA+G;AAgC/G;;;;;GAKG;AACH,SAAsB,gBAAgB,CAAC,KAA4B;;QAC/D,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;QAC7F,MAAM,KAAK,GAAsB,EAAE,CAAC;QAEpC,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC9C,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC7B,SAAS;YACb,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACjF,SAAS;YACb,CAAC;YAED,MAAM,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACxC,IAAI,SAAS,GAAG,wCAAqB,EAAE,CAAC;gBACpC,IAAA,oBAAG,GAAE,CAAC,IAAI,CAAC,gDAAgD,OAAO,CAAC,MAAM,GAAG,KAAK,gBAAgB,CAAC,CAAC;gBACnG,MAAM;YACV,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;YAClD,iGAAiG;YACjG,MAAM,GAAG,GAAG,IAAA,gCAAa,EAAC,OAAO,CAAC,CAAC;YACnC,IAAI,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,IAAA,kCAAkB,EACjC,MAAM,EACN,GAAS,EAAE,gDAAC,OAAA,IAAA,mCAAgB,EAAC,MAAM,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA,GAAA,EAC9E,gBAAgB,MAAM,CAAC,GAAG,2BAA2B,MAAM,IAAI,CAClE,CAAC;gBACF,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACnF,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACT,IAAA,oBAAG,GAAE,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,GAAG,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC/F,CAAC;oBAAS,CAAC;gBACP,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;YACtB,CAAC;QACL,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;CAAA"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Why a page was picked, in priority order: the homepage, pages that describe services, about/FAQ/financing/careers
3
+ * pages (which name licences and brands), service-area pages and brand pages.
4
+ */
5
+ export type ServicePageKind = "homepage" | "service" | "about" | "area" | "brand";
6
+ export interface ServicePage {
7
+ url: string;
8
+ kind: ServicePageKind;
9
+ }
10
+ export interface SelectServicePagesOptions {
11
+ /**
12
+ * Most pages to return, homepage included. Default `DEFAULT_MAX_SERVICE_PAGES`.
13
+ */
14
+ maxPages?: number;
15
+ /**
16
+ * Pages already discovered elsewhere, e.g. from the sitemap. Added when the homepage does not link them.
17
+ */
18
+ known?: {
19
+ aboutUs?: string;
20
+ faqPage?: string;
21
+ };
22
+ }
23
+ export declare const DEFAULT_MAX_SERVICE_PAGES = 12;
24
+ /**
25
+ * Picks the same-site pages worth reading for the services a business offers.
26
+ *
27
+ * The homepage comes first and counts against `maxPages`. When there are more candidates than room, one about,
28
+ * one service-area and one brand page are kept (while services keep at least half the room) and the rest goes to
29
+ * service pages, breadth first.
30
+ *
31
+ * @param html The homepage HTML
32
+ * @param homepageUrl The homepage URL, also the base for relative links
33
+ */
34
+ export declare function selectServicePages(html: string, homepageUrl: string, options?: SelectServicePagesOptions): ServicePage[];