@bowmark/web 1.4.0 → 1.5.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.
@@ -5,9 +5,9 @@
5
5
  // rather than imported. An `import` or `export` at the top level of this file would
6
6
  // turn it into a module and every declaration below would stop being global.
7
7
  //
8
- // Manifest version: 6368edcbec9d9ee7ceb3fd590c7054ade0542a93e43a39f4f88dc6167c0e36da
9
- // 8 capabilities, 74 providers, 233 typed functions, 20 refused.
10
- // 51,712 family members, sharing 2 interface(s) — declared once and pointed at, never repeated per member.
8
+ // Manifest version: 75ed32aa210bc375ea259fb61276ab65363d6b123ba60e63283bdfa36a58a3d5
9
+ // 8 capabilities, 87 providers, 294 typed functions, 20 refused.
10
+ // 51,713 family members, sharing 2 interface(s) — declared once and pointed at, never repeated per member.
11
11
  //
12
12
  // REFUSED — these functions are real and callable, and their declared arguments
13
13
  // carry no types, so no honest signature exists. Each one is commented in place
@@ -959,10 +959,87 @@ interface aaRetrieveBookingArgs {
959
959
  lastName: string;
960
960
  }
961
961
 
962
+ interface aaBaggageAllowanceArgs {
963
+ /** The country flown FROM — an ISO-3166 alpha-2 code ("US", "GB") or a country
964
+ * name in any capitalisation. Not an airport code: American publishes bag fees
965
+ * by region and its regions are lists of countries, and no surface on its
966
+ * estate resolves an airport to one. */
967
+ origin: string;
968
+ /** The country flown TO, same forms. */
969
+ destination: string;
970
+ }
971
+
972
+ interface aaBaggageAllowance {
973
+ origin: aaBaggageEndpoint;
974
+ destination: aaBaggageEndpoint;
975
+ /** Which row of American's fee table this trip landed on, and how. */
976
+ feeRegion: {
977
+ label: string;
978
+ matchedOn: "country" | "region" | "region-members";
979
+ matchedEndpoint: "origin" | "destination";
980
+ };
981
+ checkedBagFees: aaCheckedBagFee[];
982
+ checkedBagLimits: aaCheckedBagLimits;
983
+ carryOn: aaCarryOnAllowance;
984
+ freeCheckedBags: aaFreeCheckedBagRule[];
985
+ /** Null when American's own bag-count rule names neither end of the trip. */
986
+ maxCheckedBags: number | null;
987
+ maxCheckedBagsRules: aaMaxCheckedBagsRule[];
988
+ footnotes: string[];
989
+ sources: string[];
990
+ }
991
+
992
+ interface aaBaggageEndpoint {
993
+ input: string;
994
+ countryCode: string;
995
+ countryName: string;
996
+ /** Null for a country American files under no bag region — Mexico is the live
997
+ * case, and the fee table names it directly instead. */
998
+ region: string | null;
999
+ }
1000
+
1001
+ interface aaCheckedBagFee {
1002
+ /** "1", "2", "3", "4+". */
1003
+ bag: string;
1004
+ /** The cell verbatim, e.g. "$0 / $85*". */
1005
+ display: string;
1006
+ /** Every dollar figure in the cell, in the order printed. */
1007
+ amountsUsd: number[];
1008
+ footnoteMarkers: string[];
1009
+ }
1010
+
1011
+ interface aaCheckedBagLimits {
1012
+ maxLinearInches: number | null;
1013
+ maxLinearCm: number | null;
1014
+ maxWeightPounds: number | null;
1015
+ maxWeightKilos: number | null;
1016
+ notes: string[];
1017
+ }
1018
+
1019
+ interface aaCarryOnAllowance {
1020
+ carryOnBags: number;
1021
+ personalItems: number;
1022
+ carryOnMaxInches: number[];
1023
+ carryOnMaxCm: number[];
1024
+ personalItemMaxInches: number[];
1025
+ personalItemMaxCm: number[];
1026
+ }
1027
+
1028
+ interface aaFreeCheckedBagRule {
1029
+ bags: number;
1030
+ qualifiers: string[];
1031
+ }
1032
+
1033
+ interface aaMaxCheckedBagsRule {
1034
+ count: number;
1035
+ applies: string[];
1036
+ }
1037
+
962
1038
  /**
963
1039
  * American Airlines' own site — its published fares and award availability, flight status,
964
- * reservation lookup, seat maps, baggage allowance and fee schedules. Flight status and
965
- * reservation lookup are live and browserless; the rest are declared stubs.
1040
+ * reservation lookup, seat maps, baggage allowance and fee schedules. Flight status,
1041
+ * reservation lookup and the published baggage allowance for a route are live and browserless;
1042
+ * the rest are declared stubs.
966
1043
  */
967
1044
  interface Unit {
968
1045
  // UNTYPED, DELIBERATELY OMITTED — `getFlightStatus({ date, flightNumber, origin, destination })` declares no types for
@@ -970,6 +1047,30 @@ interface aaRetrieveBookingArgs {
970
1047
  // It is CALLABLE at runtime; `bowmark.providers.aa.getFlightStatus` is a compile error here on purpose.
971
1048
  // A `(...args: unknown[])` stand-in would compile and tell you nothing.
972
1049
 
1050
+ /**
1051
+ * American Airlines' published baggage allowance and fees for a ROUTE. `origin` and
1052
+ * `destination` are COUNTRIES — an ISO-3166 alpha-2 code ("US", "GB") or a country name
1053
+ * ("United Kingdom"), matched against American's own country list — because American prices
1054
+ * bags by REGION and publishes its regions as lists of countries ("Bag fees are based on these
1055
+ * regions"). An IATA airport code is refused with a message saying so rather than guessed at.
1056
+ * Returns the fee row American's own table lands that trip on (which region, and whether it
1057
+ * matched on the country or its region), the first, second, third and fourth-bag prices with
1058
+ * every dollar figure printed in each cell plus its footnote markers, the checked-bag weight
1059
+ * and size limits (50 lbs / 23 kgs, 62 in / 158 cm at the time of writing, with First/Business
1060
+ * and Australia/New Zealand qualifications in `notes`), the carry-on and personal-item
1061
+ * dimensions, the free-checked-bag entitlements by AAdvantage status, cabin and cardholder
1062
+ * rule, how many bags American will accept on that trip at all, and the table's own footnotes
1063
+ * verbatim. HONEST LIMITS, because they decide what this can be used for: a cell like "$0 /
1064
+ * $85*" is TWO published prices and the footnotes say which of them a given fare and status
1065
+ * pays — this function returns both rather than picking, since American's public pages do not
1066
+ * price an individual ticket and no open surface on aa.com does either. It throws rather than
1067
+ * guess for a trip where neither end is in American's domestic band (every row of the table
1068
+ * describes the other end of such a trip), and for Cuba, which American prices from two
1069
+ * separate direction-of-travel tables this function deliberately does not read as if they were
1070
+ * the same one.
1071
+ */
1072
+ getBaggageAllowance(arg0: aaBaggageAllowanceArgs): Promise<aaBaggageAllowance>;
1073
+
973
1074
  /**
974
1075
  * Reads an existing American Airlines reservation by its six-letter record locator (PNR) and
975
1076
  * the passenger's last name — nothing is signed into, and both are the caller's own details,
@@ -1337,6 +1438,79 @@ interface AshleyFurnitureStore {
1337
1438
  }
1338
1439
  }
1339
1440
 
1441
+ declare namespace BowmarkProvider_avis {
1442
+ // ── Avis — the unit's own declarations, verbatim ──
1443
+ interface avisRow {
1444
+ id: string;
1445
+ }
1446
+
1447
+ interface AvisLocationRow {
1448
+ mnemonic: string;
1449
+ name: string;
1450
+ group: string;
1451
+ address: {
1452
+ line1: string;
1453
+ line2: string | null;
1454
+ city: string;
1455
+ stateCode: string | null;
1456
+ postalCode: string | null;
1457
+ countryCode: string | null;
1458
+ countryName: string | null;
1459
+ };
1460
+ phone: string | null;
1461
+ latitude: number | null;
1462
+ longitude: number | null;
1463
+ drivableDistanceMiles: number | null;
1464
+ is24hoursDropOffAvailable: boolean;
1465
+ isKeyDropLocation: boolean;
1466
+ relPath: string | null;
1467
+ }
1468
+
1469
+ interface AvisLocationDetail extends AvisLocationRow {
1470
+ hoursOfOperation: {
1471
+ dayOfWeek: number;
1472
+ day: "SUNDAY" | "MONDAY" | "TUESDAY" | "WEDNESDAY" | "THURSDAY" | "FRIDAY" | "SATURDAY";
1473
+ intervals: { openMinute: number; closeMinute: number }[];
1474
+ isClosed: boolean;
1475
+ }[];
1476
+ holidays: { scheduleName: string; date: string }[];
1477
+ associatedLocation: { mnemonic: string | null; name: string | null } | null;
1478
+ isCorporate: boolean;
1479
+ isSelfServiceKiosk: boolean;
1480
+ isFreePickup: boolean;
1481
+ isTruck: boolean;
1482
+ isAvisFirstLocation: boolean;
1483
+ maxLengthOfRental: number | null;
1484
+ locationVehicleCategory: string | null;
1485
+ }
1486
+
1487
+ /**
1488
+ * Car rental — availability search, existing-reservation lookup and location directory on
1489
+ * avis.com. searchLocations and getLocation are live; the rest are stubs.
1490
+ */
1491
+ interface Unit {
1492
+ /**
1493
+ * Finds Avis rental locations matching a full city name or an airport code (`query`, e.g.
1494
+ * "Chicago" or "ORD" — an exact token match, not a substring or address search) off the site's
1495
+ * own location-search API, optionally narrowed to one US state (`stateCode`). Returns each
1496
+ * match's station code, display name, site grouping (airport, neighbourhood, city dock, …),
1497
+ * address, phone and coordinates. Empty array on no match, never an error.
1498
+ */
1499
+ searchLocations(args: object): Promise<AvisLocationRow[]>;
1500
+
1501
+ /**
1502
+ * Reads one Avis rental location in full off the site's own location-search API for a station
1503
+ * code (`mnemonic`, e.g. "ORD"). For an airport code, `cityName` is optional and the mnemonic
1504
+ * itself is used; for a non-airport mnemonic the caller must pass the city from a prior
1505
+ * `searchLocations` row. Returns the row's address, phone, latitude/longitude, opening hours
1506
+ * per day (with split shifts that wrap midnight), the holiday schedule, the after-hours
1507
+ * sibling (`associatedLocation`), and the full set of service flags (24h drop-off, key drop,
1508
+ * self-service kiosk, corporate, free pickup, truck, Avis First).
1509
+ */
1510
+ getLocation(args: object): Promise<AvisLocationDetail>;
1511
+ }
1512
+ }
1513
+
1340
1514
  declare namespace BowmarkProvider_azure {
1341
1515
  // ── Microsoft Azure — the unit's own declarations, verbatim ──
1342
1516
  interface AzurePriceRow {
@@ -1684,6 +1858,57 @@ interface BlendersEyewearPriceResult {
1684
1858
  }
1685
1859
  }
1686
1860
 
1861
+ declare namespace BowmarkProvider_bluehaven {
1862
+ // ── Blue Haven Pools & Spas — the unit's own declarations, verbatim ──
1863
+ interface BluehavenPoolDesign {
1864
+ id: number;
1865
+ name: string;
1866
+ category: string;
1867
+ subCategory: string | null;
1868
+ }
1869
+
1870
+ interface BluehavenSiteFeasibility {
1871
+ matchedAddress: string;
1872
+ coordinates: { lat: number; lng: number };
1873
+ apn: string | null;
1874
+ ownerName: string | null;
1875
+ lotAreaSqFt: number | null;
1876
+ existingStructures: unknown[];
1877
+ nearbyUtilityLines: { name: string; features: unknown[] }[];
1878
+ warnings: string[];
1879
+ }
1880
+
1881
+ /**
1882
+ * Blue Haven Pools & Spas' own Canibuild site-planning widget — sited lot feasibility for a
1883
+ * real US address (parcel area, existing structures, nearby utility lines) and their live
1884
+ * inground pool design catalog.
1885
+ */
1886
+ interface Unit {
1887
+ /**
1888
+ * Reads Blue Haven's own live inground pool design catalog off their site-planning widget's
1889
+ * API — every design set (e.g. Oasis, Omega, Oval, Pacific, Rectangle) under every
1890
+ * category/subcategory they currently sell (Pool Studios, Blue Haven Pools, Freeform Pools).
1891
+ * Real catalog data, not a marketing page scrape.
1892
+ */
1893
+ listPoolDesigns(): Promise<BluehavenPoolDesign[]>;
1894
+
1895
+ /**
1896
+ * Runs a US street address through Blue Haven's own site-planning tool the way their homepage
1897
+ * widget does — resolves the address, then reads back the parcel's own lot area, APN/owner
1898
+ * (when on file), any structures the site already has recorded on that parcel, and
1899
+ * utility-line hazards (electrical, oil/gas) near it. This is the address-SITED data ChatGPT's
1900
+ * own knowledge cannot produce (confirmed in this packet's ANGLE fit-check: asked to site a
1901
+ * pool at a real address, it asked the user to upload yard photos or offered a rough satellite
1902
+ * guess, and quoted a national price range instead of anything tied to the parcel). Only
1903
+ * addresses that resolve through Blue Haven's own parcel index carry sited data (most US
1904
+ * residential/commercial street addresses do); a handful of well-known landmark addresses
1905
+ * resolve only to a generic map pin and throw `BluehavenBadRequest`, same as an address with
1906
+ * no match at all.
1907
+ */
1908
+ checkPoolSiteFeasibility(args: { address: string }): Promise<BluehavenSiteFeasibility>;
1909
+ }
1910
+ }
1911
+
1687
1912
  declare namespace BowmarkProvider_bmwusa {
1688
1913
  // ── BMW USA — the unit's own declarations, verbatim ──
1689
1914
  interface BmwusaBuiltVehicleOption {
@@ -1740,6 +1965,84 @@ interface BmwusaCpoSearchOptions {
1740
1965
  maxOdometer?: number;
1741
1966
  }
1742
1967
 
1968
+ interface BmwusaModelTrim {
1969
+ name: string;
1970
+ modelCode: string | null;
1971
+ zeroToSixty: number | null;
1972
+ horsepower: number | null;
1973
+ startingMsrp: number | null;
1974
+ engineType: string | null;
1975
+ drivetrain: string | null;
1976
+ transmission: string | null;
1977
+ fuelType: string | null;
1978
+ fuelEfficiency: { city: number | null; highway: number | null; combined: number | null; unit: string } | null;
1979
+ seatingCapacity: number | null;
1980
+ }
1981
+
1982
+ interface BmwusaModel {
1983
+ name: string;
1984
+ series: string;
1985
+ url: string;
1986
+ trims: BmwusaModelTrim[];
1987
+ }
1988
+
1989
+ interface BmwusaOfferTier {
1990
+ apr: number;
1991
+ months: number;
1992
+ }
1993
+
1994
+ interface BmwusaLeaseOffer {
1995
+ code: string;
1996
+ description: string;
1997
+ monthlyPayment: number;
1998
+ term: number;
1999
+ msrp: number;
2000
+ downPayment: number;
2001
+ acquisitionFee: number;
2002
+ dueAtSigningExceptNy: number | null;
2003
+ loyaltyCredit: number | null;
2004
+ dealerContribution: string | null;
2005
+ allowedMiles: number | null;
2006
+ chargePerExcessMile: number | null;
2007
+ endOfTermPurchaseOption: number | null;
2008
+ startDate: string;
2009
+ endDate: string;
2010
+ }
2011
+
2012
+ interface BmwusaFinanceOffer {
2013
+ code: string;
2014
+ description: string;
2015
+ tiers: BmwusaOfferTier[];
2016
+ loyaltyCredit: number | null;
2017
+ startDate: string;
2018
+ endDate: string;
2019
+ }
2020
+
2021
+ interface BmwusaOffer {
2022
+ modelCode: string;
2023
+ modelName: string;
2024
+ series: string;
2025
+ bodyStyle: string;
2026
+ msrp: number;
2027
+ lease: BmwusaLeaseOffer | null;
2028
+ finance: BmwusaFinanceOffer | null;
2029
+ }
2030
+
2031
+ interface BmwusaOffersResult {
2032
+ region: string;
2033
+ offers: BmwusaOffer[];
2034
+ }
2035
+
2036
+ interface BmwusaModelListing {
2037
+ name: string;
2038
+ url: string;
2039
+ bodyStyle: string | null;
2040
+ powertrain: "electric" | "plugInHybrid" | "performance" | "gasoline" | null;
2041
+ msrpFrom: number | null;
2042
+ msrpTo: number | null;
2043
+ trimCount: number;
2044
+ }
2045
+
1743
2046
  /**
1744
2047
  * BMW US car shopping: the Build Your Own configurator and its option pricing, live VIN-level
1745
2048
  * new and Certified Pre-Owned dealer inventory near a ZIP, the model lineup with trims and
@@ -1766,6 +2069,37 @@ interface BmwusaCpoSearchOptions {
1766
2069
  * buckets, not raw numbers, so this filters honestly rather than guessing bucket boundaries).
1767
2070
  */
1768
2071
  searchCertifiedPreOwned(zip: string, options?: { radius?: number; limit?: number; model?: string; minYear?: number; maxYear?: number; maxPrice?: number; maxOdometer?: number }): Promise<BmwusaCpoVehicle[]>;
2072
+
2073
+ /**
2074
+ * Reads one BMW model's body-style page (path is the segment of the site's own
2075
+ * /vehicles/...html URL, e.g. 'x-models/x5', '2-series/coupe' — read off bmwusa.com's own
2076
+ * navigation or sitemap.xml) and returns its series, model name, and every trim BMW currently
2077
+ * sells on that page: each trim's own name, its build-your-own model code (the same code
2078
+ * buildVehicle takes), 0-60 time, horsepower, starting MSRP (null when the site shows '--' —
2079
+ * not yet published), engine type, drivetrain, transmission, fuel type, fuel efficiency (MPG
2080
+ * or MPGe) and seating capacity.
2081
+ */
2082
+ getModel(path: string): Promise<BmwusaModel>;
2083
+
2084
+ /**
2085
+ * Lists BMW's current US lease and finance offers for a 5-digit ZIP code (resolved server-side
2086
+ * to a sales region, since the site's own offer objects carry per-region eligibility) — every
2087
+ * model with an active offer, each with its own lease (monthly payment, term, MSRP, down
2088
+ * payment, due-at-signing, allowed miles, loyalty credit) and/or finance (APR tiers, loyalty
2089
+ * credit) terms, exactly as bmwusa.com's own /special-offers.html widget resolves them.
2090
+ */
2091
+ listOffers(zip: string): Promise<BmwusaOffersResult>;
2092
+
2093
+ /**
2094
+ * Lists BMW's current US lineup — every model BMW sells, with its bmwusa.com model-overview
2095
+ * URL, body style, powertrain category (electric / plug-in hybrid / performance / gasoline)
2096
+ * and starting MSRP band — so an agent can resolve a person's vague 'a BMW SUV under $60k'
2097
+ * into the specific models that exist, with their real prices, before looking up any one of
2098
+ * them. Reads /all-bmws.html for the 49-card catalog, then fans out (concurrency 5) to each
2099
+ * model-overview page for MSRP; pages with no trim table (BMW iX, certain M models) still
2100
+ * appear in the result with null MSRPs and null body style rather than dropping the model.
2101
+ */
2102
+ listModels(): Promise<BmwusaModelListing[]>;
1769
2103
  }
1770
2104
  }
1771
2105
 
@@ -1803,12 +2137,38 @@ interface cancerCentersResult {
1803
2137
  centers: cancerCenterRow[];
1804
2138
  }
1805
2139
 
2140
+ type cancerInfoAudience = "patient" | "healthProfessional";
2141
+
2142
+ interface cancerInfoSection {
2143
+ /** The PDQ document's own heading, verbatim, e.g. "Stage Information for
2144
+ * Breast Cancer". */
2145
+ heading: string;
2146
+ /** The section's own text, whitespace-normalized. */
2147
+ text: string;
2148
+ }
2149
+
2150
+ interface cancerInfoSummaryResult {
2151
+ topic: string;
2152
+ audience: cancerInfoAudience;
2153
+ /** The PDQ document's own title, verbatim. */
2154
+ title: string;
2155
+ /** The summary's own page on cancer.gov. */
2156
+ url: string;
2157
+ /** ISO 8601 — the PDQ Editorial Board's own "Updated" date for this exact
2158
+ * document. PDQ is a living, continuously revised document; there is no
2159
+ * honest way to use this text without it. */
2160
+ revisionDate: string;
2161
+ sections: cancerInfoSection[];
2162
+ }
2163
+
1806
2164
  /**
1807
2165
  * The US National Cancer Institute: PDQ cancer information, the clinical-trial register,
1808
- * cancer drugs, NCI-designated cancer centers and the cancer dictionaries. The NCI-Designated
1809
- * Cancer Center directory (`findCancerCenters`) is callable now — every center's name,
1810
- * designation type, location and host institution, optionally filtered by state; the other
1811
- * twelve declared functions are still stubs.
2166
+ * cancer drugs, NCI-designated cancer centers and the cancer dictionaries. Callable now: the
2167
+ * NCI-Designated Cancer Center directory (`findCancerCenters`) — every center's name,
2168
+ * designation type, location and host institution, optionally filtered by state and
2169
+ * `getCancerInfoSummary` NCI's own PDQ information summary for a cancer topic, patient or
2170
+ * health-professional version, with its own revision date. The other eleven declared functions
2171
+ * are still stubs.
1812
2172
  */
1813
2173
  interface Unit {
1814
2174
  /**
@@ -1824,6 +2184,121 @@ interface cancerCentersResult {
1824
2184
  * — so `total` and `centers.length` are always equal.
1825
2185
  */
1826
2186
  findCancerCenters(args?: { state?: string }): Promise<cancerCentersResult>;
2187
+
2188
+ /**
2189
+ * NCI's own PDQ information summary for one cancer topic — what the cancer is, its symptoms
2190
+ * and risk factors, how it is diagnosed and staged, the treatment options by stage, and the
2191
+ * prognosis — split into the site's own headed sections, each with its heading and text.
2192
+ * `topic` is cancer.gov's own `/types` path segment (e.g. "breast", "lung", "prostate").
2193
+ * `audience` (default `"patient"`) selects the patient-facing version or the more technical
2194
+ * health-professional one NCI maintains separately; both carry the same `document-dates`
2195
+ * revision block when the topic publishes one. `revisionDate` (ISO 8601) is the PDQ Editorial
2196
+ * Board's own "Updated" date for the exact document returned — PDQ is continuously revised, so
2197
+ * this is not decoration. English only: the Spanish path for the same topic uses different
2198
+ * words, not a parameter substitution on the English slug (breast's HP Spanish page is
2199
+ * `/espanol/tipos/seno/pro/tratamiento-seno-pdq`, not a `breast`/`hp` swap), and reaching it
2200
+ * needs its own resolver over the Spanish `/espanol/tipos` index — unbuilt. Two ways this
2201
+ * throws instead of guessing: `CancerInfoSummaryNotPublishedError` when the topic+audience has
2202
+ * no single consolidated document (NCI is mid-redesign — breast's patient content was migrated
2203
+ * to a task-based hub with no one document or date; its health-professional content is
2204
+ * unaffected), and `CancerInfoSummaryAmbiguousTopicError` when the topic's own index entry
2205
+ * covers more than one genuinely distinct disease, each with its own summary (lung:
2206
+ * non-small-cell and small-cell are both filed under `/types/lung`) — the error names every
2207
+ * option's own URL rather than silently answering for the wrong one.
2208
+ */
2209
+ getCancerInfoSummary(args: { topic: string; audience?: "patient" | "healthProfessional" }): Promise<cancerInfoSummaryResult>;
2210
+ }
2211
+ }
2212
+
2213
+ declare namespace BowmarkProvider_caraway {
2214
+ // ── Caraway Home — the unit's own declarations, verbatim ──
2215
+ interface CarawayVariant {
2216
+ /** Shopify's numeric variant id as a string. */
2217
+ id: string;
2218
+ /** The variant's own label, e.g. "Cream" or "Default Title". */
2219
+ title: string;
2220
+ /** String verbatim from the storefront — "50.00" (dollars) on /products.json, "44500" (cents) on /products/<h>.js. */
2221
+ price: string;
2222
+ /** Same scale as price. Null when the product is not on sale. */
2223
+ compareAtPrice: string | null;
2224
+ /** The store's own SKU. Null on a product without one. */
2225
+ sku: string | null;
2226
+ /** Whether the variant is purchasable right now. */
2227
+ available: boolean;
2228
+ options: string[];
2229
+ }
2230
+ interface CarawayProduct {
2231
+ /** The handle is the only stable identifier across the catalogue. */
2232
+ handle: string;
2233
+ title: string;
2234
+ vendor: string;
2235
+ productType: string;
2236
+ url: string;
2237
+ descriptionHtml: string | null;
2238
+ optionNames: string[];
2239
+ variants: CarawayVariant[];
2240
+ /** Same scale as variants — see CarawayVariant.price. */
2241
+ priceRange: { min: string; max: string } | null;
2242
+ /** True if ANY variant is purchasable. */
2243
+ inStock: boolean;
2244
+ tags: string[];
2245
+ /** Caraway's own images, in the order the storefront publishes them. */
2246
+ images: string[];
2247
+ }
2248
+ interface CarawayCatalogue {
2249
+ /** All matching products, in-stock first, then by handle. */
2250
+ products: CarawayProduct[];
2251
+ /** What the filter DROPPED, in the same register the rest of the library uses. */
2252
+ warnings: string[];
2253
+ }
2254
+ interface CarawayQuizArchetype {
2255
+ /** The archetype slug (e.g. new-customer, 90s-baby). */
2256
+ slug: string;
2257
+ /** Caraway's own copy for the archetype. */
2258
+ label: string;
2259
+ /** Caraway's own one-line archetype blurb. */
2260
+ description: string;
2261
+ /** The product handles the quiz route marks as Recommended. */
2262
+ recommendedHandles: string[];
2263
+ }
2264
+ interface CarawayQuizResult {
2265
+ /** The archetype the quiz terminal page lands on, with the site copy. */
2266
+ archetype: CarawayQuizArchetype;
2267
+ /** The Recommended rail, in stock first. */
2268
+ recommended: CarawayProduct[];
2269
+ /** What the resolver DROPPED, in the same register the rest of the library uses. */
2270
+ warnings: string[];
2271
+ }
2272
+
2273
+ /**
2274
+ * Caraway Home product catalogue — every ceramic cookware piece, its variants, real prices and
2275
+ * stock — read off the live Shopify storefront, plus the buyer-archetype rail the Caraway Home
2276
+ * Quiz terminal renders.
2277
+ */
2278
+ interface Unit {
2279
+ /**
2280
+ * Reads the live Caraway catalogue as Caraway publishes it — every product, its handle, title,
2281
+ * vendor, description, tags, images and the per-variant price the storefront is quoting right
2282
+ * now. Returns [] on a transport failure. The catalog page is the line and the parse is the
2283
+ * unit of work.
2284
+ */
2285
+ listCarawayProducts(opts?: { limit?: number }): Promise<CarawayProduct[]>;
2286
+
2287
+ /**
2288
+ * Reads one product by its handle — every variant, its exact price, the image the storefront
2289
+ * is showing and whether that specific variant is purchasable right now. Takes the handle
2290
+ * listCarawayProducts returns. THROWS on an unknown handle (the store answers a real 404).
2291
+ */
2292
+ getCarawayProduct(handle: string): Promise<CarawayProduct>;
2293
+
2294
+ /**
2295
+ * Routes a quiz's buyer-fit answers to a Caraway archetype and resolves the Recommended rail
2296
+ * the quiz terminal page renders. The archetype slug comes from the quiz's terminal URL
2297
+ * (new-customer, 90s-baby, etc.) and the rail is the live catalogue filtered to the products
2298
+ * Caraway marks for that buyer. THROWS on an unknown archetype — the supported set is encoded
2299
+ * inside the function and surfaced via the same module that owns the catalogue.
2300
+ */
2301
+ runCarawayQuiz(answers: { archetype: string }): Promise<CarawayQuizResult>;
1827
2302
  }
1828
2303
  }
1829
2304
 
@@ -1847,6 +2322,15 @@ interface carsListing {
1847
2322
  hotCar: boolean | null;
1848
2323
  dealer: { name: string | null; status: string | null } | null;
1849
2324
  }
2325
+ interface carsSearch {
2326
+ appliedFilters: { filter: string; value: string | null }[];
2327
+ totalListings: number;
2328
+ totalPages: number;
2329
+ page: number;
2330
+ pageSize: number;
2331
+ sort: string | null;
2332
+ listingIds: string[];
2333
+ }
1850
2334
  interface carsModelResearch {
1851
2335
  year: number;
1852
2336
  make: string;
@@ -1862,14 +2346,41 @@ interface carsModelResearch {
1862
2346
  expertReview: { headline: string; pros: string[]; cons: string[] } | null;
1863
2347
  whatsNew: string | null;
1864
2348
  }
2349
+ interface QuoteIdentity {
2350
+ firstName: string;
2351
+ lastName: string;
2352
+ dob: string;
2353
+ email: string;
2354
+ phone: string;
2355
+ }
2356
+ interface carsVehicleValue {
2357
+ offerCode: string;
2358
+ dealer: { name: string | null; zipCode: string | null } | null;
2359
+ tradeInOffer: number | null;
2360
+ privatePartyValue: number | null;
2361
+ marketLabel: string | null;
2362
+ mileageUsed: number | null;
2363
+ warnings: string[];
2364
+ }
1865
2365
 
1866
2366
  /**
1867
2367
  * Cars.com — the US new/used/certified car marketplace: for-sale inventory with dealer asking
1868
2368
  * prices, one listing's full detail, a valuation for a car you already own, and per-model
1869
- * research (trims, specs, expert and owner reviews). Two functions are built: reading a single
1870
- * listing in full by its id, and one model year's research overview.
2369
+ * research (trims, specs, expert and owner reviews). Three functions are built: searching the
2370
+ * inventory, reading one listing in full, and reading one year/make/model's research overview.
2371
+ * A fourth — the cash-offer valuation — is built too: callers pass a VIN, a ZIP, and the
2372
+ * caller-supplied identity the 2026-07-31 quote-flow ruling requires, and the function returns
2373
+ * the trade-in offer and private-party value perseus published for the assigned local dealer.
1871
2374
  */
1872
2375
  interface Unit {
2376
+ /**
2377
+ * Searches Cars.com's live for-sale inventory the way its own shopping results page does — by
2378
+ * ZIP and radius, new / used / certified-pre-owned, make, model, price, mileage — and returns
2379
+ * the matching listing ids (each one is a getListing argument verbatim), the total match count
2380
+ * across all pages, and the filter set the service actually applied.
2381
+ */
2382
+ search(args: { zipCode?: string; radiusMiles?: number; stockType?: 'new' | 'used' | 'cpo'; make?: string; model?: string; maxPrice?: string; minPrice?: string; maxMileage?: string; page?: number; pageSize?: number; sort?: string }): Promise<carsSearch>;
2383
+
1873
2384
  /**
1874
2385
  * Reads one cars.com listing in full by its id (the uuid in a /vehicledetail/<id>/ url): VIN,
1875
2386
  * asking price, mileage, year/make/model, stock number, CPO status, EPA highway mpg, the
@@ -1884,6 +2395,17 @@ interface carsModelResearch {
1884
2395
  * year — null/absent exactly where cars.com's own page shows nothing for it.
1885
2396
  */
1886
2397
  getModelResearch(args: { make: string; model: string; year: number }): Promise<carsModelResearch>;
2398
+
2399
+ /**
2400
+ * Reads Cars.com's own cash-offer valuation for a car the caller already owns: the trade-in
2401
+ * offer and the private-party value perseus computed for the dealer's assigned ZIP, with the
2402
+ * dealer and mileage the offer was scoped to. Identity is required (caller-supplied, per the
2403
+ * 2026-07-31 quote-flow ruling) so perseus has a person to assign the offer record to. The
2404
+ * function NEVER calls contactDealer, optinDealer, acceptByCode, smsPictureRequest or
2405
+ * media.create — the contact routes the 2026-08-06 standing decision names as the fence for a
2406
+ * cash-offer appraisal.
2407
+ */
2408
+ getVehicleValue(args: { vin: string; identity: QuoteIdentity; postalCode: string; mileage?: number }): Promise<carsVehicleValue>;
1887
2409
  }
1888
2410
  }
1889
2411
 
@@ -2232,6 +2754,32 @@ interface ClasspassScheduleOptions {
2232
2754
  days?: number;
2233
2755
  }
2234
2756
 
2757
+ interface ClasspassSearchQuery {
2758
+ /** Centre of the search, decimal degrees. */
2759
+ lat: number;
2760
+ lon: number;
2761
+ /** Search radius (default 1, clamped to 1-50). */
2762
+ radius: number;
2763
+ /** "mi" (default) or "km". */
2764
+ radiusUnits?: "mi" | "km";
2765
+ /** First day, YYYY-MM-DD. Defaults to TODAY (UTC date). */
2766
+ date?: string;
2767
+ /** Opaque page token from a previous result's `cursor`. */
2768
+ cursor?: string;
2769
+ }
2770
+
2771
+ interface ClasspassSearchResult {
2772
+ results: ClasspassVenue[];
2773
+ /** Opaque page token. Pass back as `query.cursor`; null when the last page is reached. */
2774
+ cursor: string | null;
2775
+ /** The origin's own session id — stable across pages of one search. */
2776
+ searchId: string;
2777
+ /** Always null: the origin does not publish a total. */
2778
+ totalHits: number | null;
2779
+ /** What this function did to the caller's query (defaults applied). */
2780
+ warnings: string[];
2781
+ }
2782
+
2235
2783
  /**
2236
2784
  * ClassPass — fitness, wellness and beauty classes across gyms, studios, spas and salons.
2237
2785
  * `getStudio` reads one studio's whole profile in a single request: what it does, where it is,
@@ -2241,6 +2789,28 @@ interface ClasspassScheduleOptions {
2241
2789
  * search, per-slot availability and membership pricing are declared but not built yet.
2242
2790
  */
2243
2791
  interface Unit {
2792
+ /**
2793
+ * ClassPass's own location search — POST lat/lon/radius and read back the venues in range,
2794
+ * with their identity, address, coordinates, IANA time zone, the activities the venue teaches,
2795
+ * amenities, ratings, distance and the practical details a person needs to decide which to
2796
+ * open. `query.lat` and `query.lon` are required (decimal degrees, finite, in range);
2797
+ * `query.radius` defaults to 1 and is clamped to 1-50; `query.radiusUnits` is `mi` (default)
2798
+ * or `km`; `query.date` is `YYYY-MM-DD` and defaults to TODAY (UTC). Pagination: the response
2799
+ * carries `cursor` (the base64 page token) and `searchId`; pass `cursor` back verbatim as
2800
+ * `query.cursor` on the next call — the body's shape is identical. One call returns up to 50
2801
+ * venues; the origin does not publish a total count, so `totalHits` is always `null` and the
2802
+ * caller pages until `cursor` is also null. Returns `warnings` whenever the function did
2803
+ * anything to the caller's query (radius defaulted, date defaulted) so a caller rendering the
2804
+ * result knows exactly what shape their input landed in. Each venue block carries `activities`
2805
+ * populated (the search response's `schedules[].venue.activities` is a comma-joined string the
2806
+ * parser splits), which `getSchedule`'s venue block does NOT have on a day the studio
2807
+ * publishes nothing — a real difference, not an inconsistency. **`query` shape today:** only
2808
+ * lat/lon/radius/radiusUnits/date/cursor are honored. The help center's rich facets (text
2809
+ * search, activity filter, time-of-day, credit-price band, neighbourhood) are DECLARED on
2810
+ * `search` but NOT WIRED — see manifest `notImplemented`.
2811
+ */
2812
+ search(query: ClasspassSearchQuery): Promise<ClasspassSearchResult>;
2813
+
2244
2814
  /**
2245
2815
  * Reads ONE ClassPass studio's whole profile in a single request — the page a person reads to
2246
2816
  * decide whether a result is worth booking. `studio` is a ClassPass venue id (74359), the
@@ -2378,6 +2948,76 @@ interface CloudflareSearchDomainAvailabilityResult {
2378
2948
  }
2379
2949
  }
2380
2950
 
2951
+ declare namespace BowmarkProvider_cyberpowerpc {
2952
+ // ── CyberPowerPC — the unit's own declarations, verbatim ──
2953
+ interface CyberpowerpcConfigurator {
2954
+ slug: string;
2955
+ name: string;
2956
+ url: string;
2957
+ price: string | null;
2958
+ priceValue: number | null;
2959
+ listPrice: string | null;
2960
+ listPriceValue: number | null;
2961
+ baselineSpecs: string[];
2962
+ }
2963
+ interface CyberpowerpcOption {
2964
+ id: string;
2965
+ name: string;
2966
+ sku: string | null;
2967
+ priceDifference: number;
2968
+ isDefault: boolean;
2969
+ }
2970
+ interface CyberpowerpcSection {
2971
+ code: string;
2972
+ label: string;
2973
+ category: "Core Components" | "Accessories" | "Software & Service";
2974
+ required: boolean;
2975
+ defaultOptionId: string | null;
2976
+ options: CyberpowerpcOption[];
2977
+ }
2978
+ interface CyberpowerpcCatalog {
2979
+ slug: string;
2980
+ title: string;
2981
+ basePrice: number;
2982
+ sections: CyberpowerpcSection[];
2983
+ }
2984
+ interface CyberpowerpcPriceResult {
2985
+ slug: string;
2986
+ basePrice: number;
2987
+ totalPrice: number;
2988
+ lines: { sectionCode: string; sectionLabel: string; optionId: string; optionName: string; priceDifference: number }[];
2989
+ }
2990
+
2991
+ /**
2992
+ * Reads and prices CyberPowerPC's real gaming-PC configurators — every component, every
2993
+ * option's exact price.
2994
+ */
2995
+ interface Unit {
2996
+ /**
2997
+ * Lists every base gaming-PC configurator CyberPowerPC currently sells — AMD and Intel,
2998
+ * Mainstream through Extreme — with its slug, current starting price, list price and stock
2999
+ * CPU/GPU/memory/motherboard/storage lines. Takes nothing. The slug it returns is what
3000
+ * getConfigurator and priceBuild take.
3001
+ */
3002
+ listConfigurators(): Promise<CyberpowerpcConfigurator[]>;
3003
+
3004
+ /**
3005
+ * Reads one base configurator's whole component tree — every section (CPU, GPU, memory,
3006
+ * chassis, storage, ...), every option's exact label, SKU and signed price difference versus
3007
+ * that section's default. The section codes and option ids it returns are what priceBuild
3008
+ * takes.
3009
+ */
3010
+ getConfigurator(slug: string): Promise<CyberpowerpcCatalog>;
3011
+
3012
+ /**
3013
+ * Prices an exact build for one configurator given a caller's part selections (one option id
3014
+ * per section code; any section left out uses its own default). Returns the real live total
3015
+ * the site's own configurator computes, plus a per-section breakdown of what each pick added.
3016
+ */
3017
+ priceBuild(slug: string, selections: Record<string, string>): Promise<CyberpowerpcPriceResult>;
3018
+ }
3019
+ }
3020
+
2381
3021
  declare namespace BowmarkProvider_decked {
2382
3022
  // ── DECKED — the unit's own declarations, verbatim ──
2383
3023
  // DECKED's OWN shapes — not a capability contract.
@@ -2474,6 +3114,34 @@ interface DeckedCabSideOptionResult {
2474
3114
  }
2475
3115
  }
2476
3116
 
3117
+ declare namespace BowmarkProvider_dice {
3118
+ // ── Dice — the unit's own declarations, verbatim ──
3119
+ interface DiceJobDetails {
3120
+ jobId: string;
3121
+ description: string;
3122
+ skills: string[];
3123
+ warnings: string[];
3124
+ }
3125
+ interface diceRow {
3126
+ id: string;
3127
+ }
3128
+
3129
+ /**
3130
+ * Dice — the US technology-only job board. Reaches each posting's full description and skill
3131
+ * list through Dice's own keyless MCP server at mcp.dice.com/mcp; declares tech-job search,
3132
+ * posting-detail reads, employer profiles and a company's open roles.
3133
+ */
3134
+ interface Unit {
3135
+ /**
3136
+ * Returns one Dice posting in full — the HTML description (the same document the consumer page
3137
+ * renders) and the normalized skills array — by the job id `searchJobs` returns. THROWS on a
3138
+ * missing id, on a non-existent posting (MCP returns isError), and on a transport failure, so
3139
+ * a caller can distinguish "no such job" from "empty result set".
3140
+ */
3141
+ getJob(jobId: string): Promise<DiceJobDetails>;
3142
+ }
3143
+ }
3144
+
2477
3145
  declare namespace BowmarkProvider_dickssportinggoods {
2478
3146
  // ── DICK'S Sporting Goods — the unit's own declarations, verbatim ──
2479
3147
  interface dickssportinggoodsDayHours {
@@ -2655,6 +3323,28 @@ interface dillardsProduct {
2655
3323
  variants: dillardsProductVariant[];
2656
3324
  }
2657
3325
 
3326
+ interface dillardsStoreRow {
3327
+ storeNumber: string;
3328
+ name: string;
3329
+ address1: string | null;
3330
+ address2: string | null;
3331
+ city: string;
3332
+ state: string;
3333
+ stateCode: string;
3334
+ zip: string;
3335
+ phone: string;
3336
+ url: string;
3337
+ latitude: number | null;
3338
+ longitude: number | null;
3339
+ }
3340
+
3341
+ interface dillardsFindStoresQuery {
3342
+ state?: string;
3343
+ city?: string;
3344
+ zip?: string;
3345
+ limit?: number;
3346
+ }
3347
+
2658
3348
  /**
2659
3349
  * Dillard's department store catalog, store-level stock, store locator and wedding/gift
2660
3350
  * registry search.
@@ -2735,6 +3425,23 @@ interface dillardsProduct {
2735
3425
  * through to its item page rather than handing back an unusable list.
2736
3426
  */
2737
3427
  searchRegistry(query: dillardsRegistrySearchQuery): Promise<dillardsRegistry[]>;
3428
+
3429
+ /**
3430
+ * Finds nearby Dillard's store locations the way the site's own /stores locator does — every
3431
+ * row carrying its `storeNumber` (the 4-digit id `checkStock` accepts as its `store`
3432
+ * argument), mall/anchor `name`, `address1`/`address2`, `city`, full `state` and 2-letter
3433
+ * `stateCode`, 5-digit `zip`, 10-digit `phone`, the per-store detail `url`, and the site's own
3434
+ * `latitude`/`longitude` (null when the row omits either). Pass AT LEAST ONE of `state` (full
3435
+ * name like "Ohio" or 2-letter code like "OH" — an unknown state THROWS, naming the 30 the
3436
+ * site publishes), `city` (exact, case-insensitive match against the site's own `city` field —
3437
+ * a name that does not match returns `[]`), or `zip` (5-digit US ZIP, exact match — the site
3438
+ * publishes one store per ZIP today, so this is "the store at this ZIP" without needing a
3439
+ * centroid lookup). Multiple filters narrow; a `state`+`city` request is a per-state page plus
3440
+ * a client-side city filter. Pass `limit` to trim. A query with no filters THROWS, naming
3441
+ * every one the site supports — an empty-argument call would otherwise hand back the full
3442
+ * 272-store list with no way to tell whether that was what the caller meant.
3443
+ */
3444
+ findStores(query: dillardsFindStoresQuery): Promise<dillardsStoreRow[]>;
2738
3445
  }
2739
3446
  }
2740
3447
 
@@ -2751,6 +3458,21 @@ type DiscounttireLocation =
2751
3458
  | { zip: string }
2752
3459
  | { latitude: number; longitude: number };
2753
3460
 
3461
+ /** One tire or wheel, as the site's own product read returns it. Price is
3462
+ * global across stores (verified at three AZ stores on the same sku on the
3463
+ * same day, 2026-08-07), so `getProduct` takes no storeCode even though
3464
+ * productByCode itself requires one. */
3465
+ interface DiscounttireProduct {
3466
+ code: string;
3467
+ name: string | null;
3468
+ brand: string | null;
3469
+ size: string | null;
3470
+ productType: string | null;
3471
+ url: string | null;
3472
+ price: { value: number | null; formatted: string | null } | null;
3473
+ source: string;
3474
+ }
3475
+
2754
3476
  interface DiscounttireStoreRef {
2755
3477
  code: string;
2756
3478
  name: string | null;
@@ -2806,14 +3528,68 @@ interface DiscounttireStock {
2806
3528
  source: string;
2807
3529
  }
2808
3530
 
3531
+ /** A tire size stamped on the sidewall — `225/45R17`. Strings, because the
3532
+ * site's schema declares every field as `String!`. */
3533
+ type TireSize = {
3534
+ diameter: string;
3535
+ width: string;
3536
+ aspectRatio: string;
3537
+ };
3538
+
3539
+ /** One tire product row from the size search. Same shape the site's own
3540
+ * `getProduct` reads back, except price + sku + name + brand, plus the
3541
+ * site's own star rating. */
3542
+ interface DiscounttireTireResult {
3543
+ code: string;
3544
+ name: string | null;
3545
+ brand: string | null;
3546
+ size: string | null;
3547
+ productType: string | null;
3548
+ url: string | null;
3549
+ price: { value: number | null; formatted: string | null } | null;
3550
+ /** `0.0`-`5.0`; null when the line has no reviews. */
3551
+ averageRating: number | null;
3552
+ }
3553
+
3554
+ /** What `searchTiresBySize` returns. */
3555
+ interface DiscounttireTireSizeSearch {
3556
+ /** The storeCode the operation was anchored to (a zip resolves to the
3557
+ * site's nearest store). */
3558
+ storeCode: string;
3559
+ pagination: {
3560
+ currentPage: number | null;
3561
+ numberOfPages: number | null;
3562
+ pageSize: number | null;
3563
+ totalNumberOfResults: number | null;
3564
+ };
3565
+ /** The site's facet names — `Brands`, `Aspect Ratio`, `Price Range`, … */
3566
+ facets: string[];
3567
+ results: DiscounttireTireResult[];
3568
+ source: string;
3569
+ }
3570
+
2809
3571
  /**
2810
3572
  * America's largest independent tire and wheel retailer — which tires and wheels actually fit
2811
3573
  * a given vehicle, what they cost, whether they are in stock near a ZIP, when a store can
2812
- * install them, and the rebates running on them. One function is built: `checkStock` answers
2813
- * whether a specific tire or wheel is gettable near a ZIP, store or coordinate, and on what
2814
- * date. The other fourteen are declared stubs.
3574
+ * install them, and the rebates running on them. Three functions are built: `getProduct` reads
3575
+ * one tire or wheel by its sku (name, brand, size, product type, price, product URL),
3576
+ * `checkStock` answers whether a specific tire or wheel is gettable near a ZIP, store or
3577
+ * coordinate, and on what date, and `searchTiresBySize` searches the tires Discount Tire sells
3578
+ * in a given size (or staggered pair) with prices, ratings and the site's pagination. The
3579
+ * other twelve are declared stubs.
2815
3580
  */
2816
3581
  interface Unit {
3582
+ /**
3583
+ * Reads one tire or wheel product by its sku — name, brand, size, product type, product URL,
3584
+ * and price (value and formatted string). Takes the numeric sku the site's product URLs end in
3585
+ * (/p/<code>), or such a URL. Price is global across stores (verified at three AZ stores on
3586
+ * the same sku on the same day, 2026-08-07), so this function takes no storeCode even though
3587
+ * the underlying `productByCode` operation requires one — the requirement is a schema
3588
+ * compliance constraint, not a per-caller choice. Throws on the site's all-null not-found row,
3589
+ * so a delisted sku surfaces as an error rather than as a row whose every field is null.
3590
+ */
3591
+ getProduct(idOrUrl: string): Promise<DiscounttireProduct>;
3592
+
2817
3593
  /**
2818
3594
  * Answers whether one specific tire or wheel is actually gettable near a place, and when — the
2819
3595
  * site's own availability sentence for the store it resolves to ("Available as soon as
@@ -2827,6 +3603,21 @@ interface DiscounttireStock {
2827
3603
  * "on the shelf right now".
2828
3604
  */
2829
3605
  checkStock(idOrUrl: string, location: { zip: string } | { storeCode: string } | { latitude: number; longitude: number }): Promise<DiscounttireStock>;
3606
+
3607
+ /**
3608
+ * Searches the tires Discount Tire sells in a given size (or staggered pair — `front` and a
3609
+ * different `rear`) and returns what is in stock near a place with prices and star ratings.
3610
+ * `front` and `rear` are stamped-on-the-sidewall sizes like `{ diameter: "17", width: "225",
3611
+ * aspectRatio: "45" }` for `225/45R17`; the site's schema refuses any unknown field on a
3612
+ * `TireSizeInput`, so the function does too. `location` is a 5-digit US zip, an exact store
3613
+ * code, or a coordinate — same three forms `checkStock` takes, same resolution path (zip is
3614
+ * geocoded to its centroid first, then the resolved store is the one the GraphQL operation is
3615
+ * anchored to). `pageNumber` and `pageSize` paginate the result set (pageSize capped at 100).
3616
+ * Returns pagination, the site's own facet list, and a list of tire rows. No
3617
+ * `vehicleAssemblyId` is needed — unlike the by-vehicle searches here, the by-size operations
3618
+ * take `vehicleInfo` as optional and the function never asks for one.
3619
+ */
3620
+ searchTiresBySize(args: { front: { diameter: string; width: string; aspectRatio: string }; rear?: { diameter: string; width: string; aspectRatio: string }; location: { zip: string } | { storeCode: string } | { latitude: number; longitude: number }; pageNumber: number; pageSize: number }): Promise<DiscounttireTireSizeSearch>;
2830
3621
  }
2831
3622
  }
2832
3623
 
@@ -3072,14 +3863,38 @@ interface ExtraspaceNearbyFacility {
3072
3863
  distanceMiles: number | null;
3073
3864
  }
3074
3865
 
3866
+ interface ExtraspaceAvailabilityResult {
3867
+ storeId: number;
3868
+ /** Normalized the way search's unitSize option is, e.g. "10x10". */
3869
+ unitSize: string;
3870
+ /** Every unit CLASS matching the requested size; empty if the facility carries none. */
3871
+ matches: ExtraspaceUnitAvailability[];
3872
+ }
3873
+
3874
+ interface ExtraspaceUnitAvailability {
3875
+ sizeDisplay: string;
3876
+ sizeClass: string;
3877
+ widthFeet: number | null;
3878
+ depthFeet: number | null;
3879
+ squareFeet: number | null;
3880
+ /** Whether the site is currently offering THIS class for rent. */
3881
+ available: boolean;
3882
+ unitsAvailable: number | null;
3883
+ streetRate: number | null;
3884
+ webRate: number | null;
3885
+ promotions: string[];
3886
+ features: string[];
3887
+ }
3888
+
3075
3889
  /**
3076
3890
  * Extra Space Storage — self-storage facility search and detail. `search` takes a US city or
3077
3891
  * ZIP and returns the nearby facilities its own locator would, nearest first, each with its
3078
3892
  * address, distance, amenities and the real monthly price of the cheapest unit in every size
3079
3893
  * it carries. `getFacility` reads one of them in full: street address, both phone lines,
3080
3894
  * office and gate-access hours, what its units offer, starting prices, rating, driving
3081
- * directions and the nearby facilities. Per-size availability and published deals are declared
3082
- * but not built yet.
3895
+ * directions and the nearby facilities. `checkAvailability` checks one specific unit size at
3896
+ * one facility and returns every unit class that matches it, each with its own live
3897
+ * availability and price. Published deals are declared but not built yet.
3083
3898
  */
3084
3899
  interface Unit {
3085
3900
  /**
@@ -3119,6 +3934,26 @@ interface ExtraspaceNearbyFacility {
3119
3934
  * caller-fixable error rather than returning an empty-looking result.
3120
3935
  */
3121
3936
  getFacility(storeId: number | string): Promise<ExtraspaceFacilityDetail>;
3937
+
3938
+ /**
3939
+ * Checks current availability and price for one unit SIZE (e.g. "10x10", "5x15" — width x
3940
+ * depth, in feet) at one Extra Space Storage facility. `storeId` is the same id
3941
+ * `search`/`getFacility` take. Returns every unit CLASS at that facility whose dimensions
3942
+ * match the requested size — a facility routinely lists more than one class of the same
3943
+ * nominal size (a live capture of facility 300125 carries four separate `10' x 10'` classes
3944
+ * with different availability), so this never collapses them to one "best" answer the way
3945
+ * `search`'s roll-up does. Each match reports whether the site is CURRENTLY offering it
3946
+ * (`available`), how many units of that class are free (`unitsAvailable`), both the
3947
+ * struck-through "street" rate and the real "web" rate, any active move-in promotion, and the
3948
+ * class's own features. An empty `matches` array means the facility does not carry that size
3949
+ * at all — a coming-soon facility with zero listed unit classes returns `matches: []` for any
3950
+ * size, with no error, exactly like a fully-open facility that simply does not offer it.
3951
+ * `unitSize` outside `width x depth` form (e.g. "12x40", which nothing in this fixture
3952
+ * carries) is not refused as invalid — it is a value the site may or may not stock, so it is
3953
+ * looked up and answered with an empty array like any other size the facility does not have;
3954
+ * only a string that cannot be PARSED as `<number>x<number>` is a caller error.
3955
+ */
3956
+ checkAvailability(storeId: number | string, unitSize: string): Promise<ExtraspaceAvailabilityResult>;
3122
3957
  }
3123
3958
  }
3124
3959
 
@@ -3288,21 +4123,177 @@ interface fordNameplateDirectory {
3288
4123
  nameplates: fordNameplate[];
3289
4124
  }
3290
4125
 
4126
+ interface fordOfferProgram {
4127
+ id: string;
4128
+ name: string;
4129
+ /** Ford's own program type, verbatim — "Cash", "APR", and whatever else
4130
+ * Ford introduces. */
4131
+ type: string;
4132
+ /** Whole USD, negative for a discount. null when this program is not a
4133
+ * flat-amount one. */
4134
+ amount: number | null;
4135
+ /** null when this program is not a financing offer. Ford sends one term or
4136
+ * several (e.g. 36/48/60/72/84-month options on the same program). */
4137
+ aprTerms: { apr: number; termMonths: number }[] | null;
4138
+ startDate: string | null;
4139
+ endDate: string | null;
4140
+ disclaimer: string | null;
4141
+ /** Ford's own machine code, e.g. "PC_STANDALONE_APR", "DEALER_CASH". */
4142
+ programType: string | null;
4143
+ /** "Retail" (public), "Private" (military/loyalty/first-responder —
4144
+ * eligibility this function cannot itself verify), "Campaign", or
4145
+ * whatever else Ford uses. */
4146
+ category: string | null;
4147
+ /** True when Ford Motor Credit finances the program. */
4148
+ financeCompany: boolean;
4149
+ /** Ford's own flag for "eligibility depends on something beyond make/model/
4150
+ * ZIP" (military status, trade-in, loyalty). */
4151
+ conditional: boolean;
4152
+ }
4153
+
4154
+ interface fordTrimOffers {
4155
+ trim: string;
4156
+ programs: fordOfferProgram[];
4157
+ }
4158
+
4159
+ interface fordOffers {
4160
+ /** The inventory slug this was resolved from, e.g. "f150". */
4161
+ nameplate: string;
4162
+ modelYear: number;
4163
+ /** The ZIP that was searched — incentives are regional. */
4164
+ postalCode: string;
4165
+ /** Ford's own dealer-region code for that ZIP (e.g. "F48B"), when it sends
4166
+ * one. Opaque outside Ford. */
4167
+ region: string | null;
4168
+ trims: fordTrimOffers[];
4169
+ }
4170
+
4171
+ interface fordVehicleImage {
4172
+ url: string;
4173
+ /** "primary", "exterior" or "interior" — search results carry "primary"
4174
+ * only; this endpoint returns the full set. */
4175
+ role: string;
4176
+ width: number | null;
4177
+ height: number | null;
4178
+ }
4179
+
4180
+ interface fordVehiclePricing {
4181
+ msrp: number;
4182
+ /** null when Ford has no net figure for this vehicle. */
4183
+ netPriceAfterIncentives: number | null;
4184
+ currency: string;
4185
+ /** Ford's own required legal text — show it alongside any displayed price. */
4186
+ disclaimer: string;
4187
+ }
4188
+
4189
+ interface fordVehicleAvailability {
4190
+ /** "in_stock", "in_transit", or a new value Ford introduces. */
4191
+ status: string;
4192
+ asOf: string;
4193
+ }
4194
+
4195
+ interface fordVehicleDealer {
4196
+ name: string;
4197
+ city: string;
4198
+ state: string;
4199
+ distanceMiles: number;
4200
+ phone: string | null;
4201
+ address: string | null;
4202
+ websiteUrl: string | null;
4203
+ }
4204
+
4205
+ interface fordVehicleOptionPackage {
4206
+ name: string;
4207
+ /** null when Ford prices the package into the vehicle's MSRP rather than
4208
+ * itemizing it. */
4209
+ msrp: number | null;
4210
+ }
4211
+
4212
+ interface fordVehicle {
4213
+ vin: string;
4214
+ /** The slug `listNameplates` returns, e.g. "f150", "explorer". */
4215
+ nameplate: string;
4216
+ displayName: string;
4217
+ year: number;
4218
+ trim: string;
4219
+ bodyStyle: string | null;
4220
+ powertrain: string | null;
4221
+ drivetrain: string | null;
4222
+ exteriorColor: string | null;
4223
+ pricing: fordVehiclePricing;
4224
+ availability: fordVehicleAvailability;
4225
+ dealer: fordVehicleDealer;
4226
+ images: fordVehicleImage[];
4227
+ /** Canonical detail page — link every vehicle mention here. */
4228
+ vdpUrl: string;
4229
+ optionPackages: fordVehicleOptionPackage[];
4230
+ }
4231
+
4232
+ interface fordRecallRecord {
4233
+ /** Ford's own campaign identifier, e.g. "23S37", "26S48". */
4234
+ campaignNumber: string | null;
4235
+ title: string | null;
4236
+ /** Issue date as Ford stores it. */
4237
+ issueDate: string | null;
4238
+ description: string | null;
4239
+ safetyRisk: string | null;
4240
+ remedy: string | null;
4241
+ status: string | null;
4242
+ /** True when this is a Field Service Action / Customer Satisfaction Program
4243
+ * (an FSA, NOT a regulator-mandated recall). */
4244
+ isCustomerSatisfactionProgram: boolean;
4245
+ }
4246
+
4247
+ interface fordVehicleRecalls {
4248
+ vin: string;
4249
+ vehicle: {
4250
+ year: string | null;
4251
+ make: string | null;
4252
+ model: string | null;
4253
+ bodyStyle: string | null;
4254
+ fuelType: string | null;
4255
+ };
4256
+ recalls: fordRecallRecord[];
4257
+ customerSatisfactionPrograms: fordRecallRecord[];
4258
+ counts: {
4259
+ recallsCount: number;
4260
+ cspCount: number;
4261
+ totalFsaCount: number;
4262
+ };
4263
+ /** True when the page acknowledges an empty result for this VIN (no
4264
+ * recalls, no FSAs) rather than an error. Ford's own empty-state copy. */
4265
+ noRecalls: boolean;
4266
+ /** True when the upstream recall service failed to answer — the page
4267
+ * surfaces its own API-error message in that case. */
4268
+ apiError: boolean;
4269
+ warnings: string[];
4270
+ }
4271
+
3291
4272
  /**
3292
4273
  * Ford US new-vehicle shopping: live VIN-level dealer inventory near a ZIP, one vehicle by
3293
4274
  * VIN, the model/trim directory and its paint palette, the build-and-price configurator, model
3294
- * specs and MSRP, current incentives, the dealer locator, and recall lookup by VIN. Two
4275
+ * specs and MSRP, current incentives, the dealer locator, and recall lookup by VIN. Five
3295
4276
  * functions are callable now. The dealer locator returns Ford dealers near a US ZIP with full
3296
4277
  * address, phone, coordinates, per-day sales and service hours, Ford's own capability flags
3297
4278
  * (EV-certified, commercial fleet, pickup-and-delivery) and links to the dealer's own site and
3298
4279
  * inventory. The nameplate directory returns every Ford model inventory can be searched by —
3299
4280
  * slug, display name, aliases, body style, model years and trims — and resolves a person's own
3300
- * words ("F-150", "mach e", "Super Duty") to the slug the other inventory endpoints take. The
3301
- * other seven declared functions are still stubs.
4281
+ * words ("F-150", "mach e", "Super Duty") to the slug the other inventory endpoints take.
4282
+ * `getOffers` returns Ford's live, ZIP-regional incentives for a model — cash back, APR
4283
+ * financing (with every term Ford offers, not just the headline one) and any lease programs,
4284
+ * each with its own dates, disclaimer and eligibility category, broken out per trim.
4285
+ * `getVehicle` reads one specific vehicle by VIN — full trim, pricing with Ford's required
4286
+ * disclaimer, availability, the holding dealer's contact details, the FULL image set (exterior
4287
+ * AND interior, not just the one card image a search result carries) and every option package
4288
+ * — and returns `null` rather than throwing when Ford reports the vehicle sold or removed,
4289
+ * which its own docs call a real, non-retryable answer. `getRecalls` returns the open safety
4290
+ * recalls and Customer Satisfaction Programs Ford has published against a VIN — campaign
4291
+ * number, issue date, description, safety risk and remedy for each — splitting
4292
+ * regulator-mandated recalls from Ford's own goodwill FSAs, with `null` for a well-formed VIN
4293
+ * Ford has no record of and an empty result (no recalls, no FSAs) for a known VIN with no open
4294
+ * actions. The other four declared functions are still stubs.
3302
4295
  */
3303
4296
  interface Unit {
3304
- // NO TYPED SURFACE — every function this unit declares is refused above.
3305
- // The unit is real and callable at runtime; nothing here can say so in types.
3306
4297
  // UNTYPED, DELIBERATELY OMITTED — `findDealers({ near, radiusMiles, limit })` declares no types for
3307
4298
  // its argument, so there is no honest signature to emit.
3308
4299
  // It is CALLABLE at runtime; `bowmark.providers.ford.findDealers` is a compile error here on purpose.
@@ -3312,6 +4303,52 @@ interface fordNameplateDirectory {
3312
4303
  // its argument, so there is no honest signature to emit.
3313
4304
  // It is CALLABLE at runtime; `bowmark.providers.ford.listNameplates` is a compile error here on purpose.
3314
4305
  // A `(...args: unknown[])` stand-in would compile and tell you nothing.
4306
+
4307
+ /**
4308
+ * Ford's current incentives for one model near a US ZIP — cash back, APR financing (every term
4309
+ * Ford offers on a program, e.g. 36/48/60/72/84-month options, not just the headline rate) and
4310
+ * any lease programs — broken out per trim, each with its start/end date, Ford's own
4311
+ * disclaimer text, its machine program code, and a `category` ("Retail" public vs. "Private"
4312
+ * military/loyalty/first-responder) so a caller can tell a program anyone qualifies for from
4313
+ * one that needs proof this function cannot itself check. `nameplate` is the slug
4314
+ * `listNameplates` returns ("f150", "bronco-sport"); a handful of commercial-chassis
4315
+ * nameplates the inventory API lists have no incentives page at all and are refused by name,
4316
+ * measured rather than guessed. `postalCode` is required — incentives are regional, and the
4317
+ * SAME model/year at two ZIPs 2,000 miles apart returns genuinely different programs. `year`
4318
+ * defaults to the newest model year Ford is currently running incentives on for that
4319
+ * nameplate.
4320
+ */
4321
+ getOffers(args: { nameplate: string; postalCode: string; year?: number }): Promise<fordOffers>;
4322
+
4323
+ /**
4324
+ * Reads one specific vehicle by its 17-character VIN — full trim, exterior color, complete
4325
+ * pricing with Ford's required disclaimer, live availability, the holding dealer's
4326
+ * name/address/phone/website, the FULL image set (`primary`, `exterior` AND `interior` — a
4327
+ * `searchInventory` result carries `primary` only), every option package, and the canonical
4328
+ * `vdpUrl` Ford's own docs say to link on any mention. `vin` is a required argument, matching
4329
+ * Ford's own pattern (17 characters, excluding I/O/Q) and checked locally before spending a
4330
+ * request. Returns `null` — not an error — when Ford answers `VEHICLE_NOT_FOUND`: Ford's own
4331
+ * docs call a 404 here "sold or removed... not a retryable error", so a vehicle that sold
4332
+ * between search and read is a real, unsurprising answer rather than a failure.
4333
+ */
4334
+ getVehicle(vin: string): Promise<fordVehicle | null>;
4335
+
4336
+ /**
4337
+ * Reads the open safety recalls and Customer Satisfaction Programs (FSAs) Ford has published
4338
+ * against one specific VIN, and what each one says to do — the same answer an owner or a
4339
+ * used-car buyer gets on Ford's owner-support recalls page. `vin` is required and locally
4340
+ * validated against the same 17-character pattern `getVehicle` uses (A-H, J-N, P, R-Z, 0-9).
4341
+ * Returns `null` — not an error — when the VIN is well-formed but unknown to Ford (the page
4342
+ * sets `isVinInvalid: true`); the call surfaces `noRecalls: true` for a known VIN with no open
4343
+ * actions, and the response separates regulator-mandated `recalls` from optional
4344
+ * `customerSatisfactionPrograms` (the latter are Ford's free goodwill fixes, NOT safety
4345
+ * recalls). Each record carries Ford's own campaign number, issue date, the free-form
4346
+ * description, the stated safety risk, the prescribed remedy, and the status Ford reports.
4347
+ * When Ford's recall upstream fails, the call returns a successful shape with `apiError: true`
4348
+ * and the upstream's own error message in `warnings` — a transient 5xx shouldn't kill the
4349
+ * caller. No sign-in: the page is public.
4350
+ */
4351
+ getRecalls(vin: string): Promise<fordVehicleRecalls | null>;
3315
4352
  }
3316
4353
  }
3317
4354
 
@@ -3436,9 +4473,42 @@ interface fredSeries {
3436
4473
  notes: string | null;
3437
4474
  }
3438
4475
 
4476
+ interface fredCategoryRow {
4477
+ id: number;
4478
+ name: string;
4479
+ parentId: number;
4480
+ }
4481
+
4482
+ interface fredCategory {
4483
+ id: number;
4484
+ name: string;
4485
+ parentId: number;
4486
+ children: fredCategoryRow[];
4487
+ series: fredSeries[];
4488
+ }
4489
+
4490
+ interface fredObservation {
4491
+ date: string;
4492
+ /** null where FRED holds no observation for that period — a market holiday in a
4493
+ * daily series, or the first year of a year-over-year transform. */
4494
+ value: number | null;
4495
+ }
4496
+
4497
+ interface fredObservations {
4498
+ seriesId: string;
4499
+ /** The transform FRED reports having applied: "lin" (none), "pc1", "pch", … */
4500
+ units: string;
4501
+ observationStart: string;
4502
+ observationEnd: string;
4503
+ realtimeStart: string;
4504
+ realtimeEnd: string;
4505
+ count: number;
4506
+ observations: fredObservation[];
4507
+ }
4508
+
3439
4509
  /**
3440
- * US economic data releases and their publication calendar, and the agencies FRED republishes
3441
- * data from, off the St. Louis Fed's FRED.
4510
+ * US economic data releases and their publication calendar, the agencies FRED republishes data
4511
+ * from, series metadata, and FRED's own category tree, off the St. Louis Fed's FRED.
3442
4512
  */
3443
4513
  interface Unit {
3444
4514
  /**
@@ -3472,6 +4542,34 @@ interface fredSeries {
3472
4542
  * back as a caller-fixable error naming the problem rather than as an empty result.
3473
4543
  */
3474
4544
  getSeriesInfo(seriesId: string): Promise<fredSeries>;
4545
+
4546
+ /**
4547
+ * Reads the actual numbers for a FRED series — the dated observations themselves, oldest
4548
+ * first, with a missing period returned as `value: null` rather than as a `NaN` or a silently
4549
+ * dropped row. Called bare (`getSeriesObservations("GDPC1")`) it returns the series' full
4550
+ * history; `from`/`to` (ISO yyyy-mm-dd) narrow the window. It also runs FRED's own transforms
4551
+ * server-side so a caller never has to recompute one: `units` converts the level to a change
4552
+ * (`pc1` percent change from a year ago — the usual way to read inflation off CPIAUCSL — plus
4553
+ * `pch`, `chg`, `log` and the rest of FRED's ten codes), and `frequency` with
4554
+ * `aggregationMethod` collapses a series to a coarser period (`{ frequency: "a",
4555
+ * aggregationMethod: "avg" }` turns the monthly unemployment rate into annual averages). The
4556
+ * result carries the transform FRED reports having applied and the vintage it served, so a
4557
+ * caller can tell what they actually got. This is the function to call once
4558
+ * `searchSeries`/`getSeriesInfo` has identified the right series id — e.g. A191RL1Q225SBEA for
4559
+ * the US real GDP growth rate.
4560
+ */
4561
+ getSeriesObservations(args: string | { seriesId: string; from?: string; to?: string; units?: string; frequency?: string; aggregationMethod?: string }): Promise<fredObservations>;
4562
+
4563
+ /**
4564
+ * Browses FRED's category tree the way fred.stlouisfed.org/categories does — the category
4565
+ * itself (id/name/parent), its immediate child categories, and the series filed directly under
4566
+ * it (the same shape getSeriesInfo returns per series, so a caller can read
4567
+ * units/frequency/lastUpdated off a browsed result with no second call). Called bare it starts
4568
+ * at the root (id 0). FRED organizes its ~800,000 series into a real hierarchy, so this is how
4569
+ * a caller explores 'what's available in this area' before knowing a series id to look up
4570
+ * directly. An unknown category id comes back as a caller-fixable error.
4571
+ */
4572
+ browseCategory(categoryId?: number): Promise<fredCategory>;
3475
4573
  }
3476
4574
  }
3477
4575
 
@@ -3912,6 +5010,15 @@ interface graingerRow {
3912
5010
  id: string;
3913
5011
  }
3914
5012
 
5013
+ interface graingerSearchRow {
5014
+ itemNumber: string;
5015
+ name: string;
5016
+ url: string;
5017
+ brand: string | null;
5018
+ price: { amount: number; currency: string; perUnit: string } | null;
5019
+ thumbnail: string | null;
5020
+ }
5021
+
3915
5022
  interface graingerBranchRow {
3916
5023
  branchNumber: string;
3917
5024
  name: string;
@@ -3922,12 +5029,55 @@ interface graingerBranchRow {
3922
5029
  hours: { day: string; hours: string }[];
3923
5030
  }
3924
5031
 
5032
+ interface graingerProductRow {
5033
+ itemNumber: string;
5034
+ manufacturerModel: string | null;
5035
+ name: string;
5036
+ description: string | null;
5037
+ brand: string | null;
5038
+ url: string;
5039
+ images: string[];
5040
+ price: { amount: number; currency: string; perUnit: string } | null;
5041
+ specs: { name: string; value: string }[];
5042
+ availabilitySummary: string | null;
5043
+ }
5044
+
5045
+ interface graingerStockRow {
5046
+ itemNumber: string;
5047
+ zip: string;
5048
+ quantity: number;
5049
+ shipping: { message: string | null; fulfillmentCode: string | null; availKey: string | null } | null;
5050
+ pickup: {
5051
+ message: string | null;
5052
+ fulfillmentCode: string | null;
5053
+ availKey: string | null;
5054
+ branch: {
5055
+ branchCode: string;
5056
+ city: string | null;
5057
+ address: { street: string | null; city: string | null; state: string | null; zip: string | null; country: string | null } | null;
5058
+ url: string | null;
5059
+ } | null;
5060
+ } | null;
5061
+ }
5062
+
3925
5063
  /**
3926
- * Grainger's industrial MRO catalog, product detail, and branch/stock availability —
3927
- * findBranch is live (nationwide branch directory, address/phone/hours); catalog, product
3928
- * detail and stock checks are still stubs.
5064
+ * Grainger's industrial MRO catalog, product detail, and branch/stock availability — search
5065
+ * (keyword/category catalog search returning name, item number, brand, price and thumbnail),
5066
+ * findBranch (nationwide branch directory), getProduct (price, pack size, spec table,
5067
+ * availability by item number or URL) and checkStock (shipping-to-zip and
5068
+ * pickup-at-nearest-branch fulfillment estimates) are all live.
3929
5069
  */
3930
5070
  interface Unit {
5071
+ /**
5072
+ * Searches Grainger's industrial MRO catalog by keyword, returning matching products — item
5073
+ * number, name, brand, list price and thumbnail. Takes `query` (free text, e.g. "antistatic
5074
+ * gloves"). A SPECIFIC query resolves to Grainger's own matching leaf category and returns its
5075
+ * real products; a broad query (e.g. "gloves" alone) can resolve to a category-of-categories
5076
+ * browse page one or more levels above any actual product and throws rather than returning an
5077
+ * empty array — narrow the query if that happens.
5078
+ */
5079
+ search(args: object): Promise<graingerSearchRow[]>;
5080
+
3931
5081
  /**
3932
5082
  * Finds Grainger's own U.S. branches near a ZIP, city or state — address, phone, hours and
3933
5083
  * curbside-pickup availability, off the site's own nationwide directory. `zip` matches by its
@@ -3937,6 +5087,26 @@ interface graingerBranchRow {
3937
5087
  * truncating.
3938
5088
  */
3939
5089
  findBranch(args: object): Promise<graingerBranchRow[]>;
5090
+
5091
+ /**
5092
+ * Reads one Grainger product page in full — price and pack size/unit of measure, the full spec
5093
+ * table, the manufacturer's own part number, and a shipping/pickup availability summary. Takes
5094
+ * `itemNumber` (Grainger's own catalog id, e.g. "26K909" — resolves directly, no descriptive
5095
+ * slug needed) or `url` (a full grainger.com product URL). Throws if the item number doesn't
5096
+ * exist (a clean 404) rather than returning an empty row.
5097
+ */
5098
+ getProduct(args: object): Promise<graingerProductRow>;
5099
+
5100
+ /**
5101
+ * Checks real fulfillment availability for one item (`itemNumber` or `url`, same as
5102
+ * `getProduct`) at a caller-supplied `zip` (required, 5-digit US) — both shipping-to-that-zip
5103
+ * and pickup-at-the-nearest-branch-to-that-zip, in one call. Returns the site's own message
5104
+ * text (an arrival/ready-by estimate, never a literal stock count — the site doesn't publish
5105
+ * one) plus its opaque status codes for each mode, and the ACTUAL branch that answered the
5106
+ * pickup half (nearest-to-point, not necessarily one the caller could have named). Optional
5107
+ * `quantity` (default 1) is forwarded to the site.
5108
+ */
5109
+ checkStock(args: object): Promise<graingerStockRow>;
3940
5110
  }
3941
5111
  }
3942
5112
 
@@ -4734,6 +5904,72 @@ interface HellofreshRecipeSearchPage {
4734
5904
  }
4735
5905
  }
4736
5906
 
5907
+ declare namespace BowmarkProvider_hellotend {
5908
+ // ── Tend Dental — the unit's own declarations, verbatim ──
5909
+ interface HellotendMarket {
5910
+ slug: string; // e.g. "new-york-city"
5911
+ name: string; // e.g. "New York City"
5912
+ location: { lat: number; lon: number } | null;
5913
+ bookingEnabled: boolean;
5914
+ }
5915
+ interface HellotendStudio {
5916
+ slug: string; // e.g. "hells-kitchen" — what listServices takes
5917
+ name: string;
5918
+ market: string; // e.g. "new-york-city"
5919
+ address: string | null;
5920
+ location: { lat: number; lon: number } | null;
5921
+ openingDate: string | null;
5922
+ serviceCodes: string[]; // ["CLNCHK","WHTNG",...] — the codes this studio accepts
5923
+ bookingEnabled: boolean;
5924
+ familyBookingEnabled: boolean;
5925
+ }
5926
+ interface HellotendService {
5927
+ code: string | null; // e.g. "CLNCHK" — null on category-level entries
5928
+ name: string; // e.g. "Exam"
5929
+ longName: string | null; // e.g. "Dental Exam"
5930
+ description: string | null;
5931
+ bookingDescription: string | null;
5932
+ duration: string | null; // e.g. "70 minutes or less"
5933
+ }
5934
+
5935
+ /**
5936
+ * Reads Tend Dental's public booking chain — every market, every studio, every service a
5937
+ * studio offers — straight from hellotend.com's own Next.js data route, no key, no browser.
5938
+ */
5939
+ interface Unit {
5940
+ /**
5941
+ * Lists every market Tend serves — the 6 metros the booking chain currently offers (NYC,
5942
+ * Washington DC, Atlanta, Boston, Chicago, Nashville), with each market's slug, lat/lon and
5943
+ * booking-enabled flag. Takes nothing. The slug it returns is what listStudios and
5944
+ * listServices take. THROWS rather than returning [] when the data route answers without its
5945
+ * payload or names no markets — Tend operates 6 metros and zero is never an honest answer.
5946
+ */
5947
+ listMarkets(): Promise<HellotendMarket[]>;
5948
+
5949
+ /**
5950
+ * Lists every Tend dental studio — 33+ across all markets, with name, slug, market, address,
5951
+ * lat/lon, opening date, the service codes that studio accepts, and whether it offers
5952
+ * family-booking. The market arg is OPTIONAL: omit it to get the full set across all markets,
5953
+ * pass a market slug to filter. THROWS rather than returning [] when the data route answers
5954
+ * without its payload or names no studios; surfaces an unknown market slug as a caller-fixable
5955
+ * error listing the real ones.
5956
+ */
5957
+ listStudios(market?: string): Promise<HellotendStudio[]>;
5958
+
5959
+ /**
5960
+ * Lists the service codes a specific Tend studio offers (Dental Exam CLNCHK, Clear Aligners
5961
+ * INVISALN, Emergency EMGNCY, Sleep Apnea Consult SLPCONS, Cosmetic, Procedures) with each
5962
+ * service's display name, code, duration and short description. The CODE is what a real Tend
5963
+ * booking needs to advance to the time-picker page. The first four carry a code; the last two
5964
+ * (Cosmetic, Procedures) are category-level landing entries that route to sub-flows and are
5965
+ * returned with a null code rather than dropped. THROWS rather than returning [] when the data
5966
+ * route answers without its payload or names no services; surfaces an unknown studio as a
5967
+ * caller-fixable error listing the real ones in that market.
5968
+ */
5969
+ listServices(market: string, studio: string): Promise<HellotendService[]>;
5970
+ }
5971
+ }
5972
+
4737
5973
  declare namespace BowmarkProvider_hilton {
4738
5974
  // ── Hilton — the unit's own declarations, verbatim ──
4739
5975
  interface hiltonRoomOffer {
@@ -5979,6 +7215,99 @@ interface InteriorDefineCartHandoff {
5979
7215
  }
5980
7216
  }
5981
7217
 
7218
+ declare namespace BowmarkProvider_joybird {
7219
+ // ── Joybird — the unit's own declarations, verbatim ──
7220
+ interface JoybirdConfigurator {
7221
+ slug: string;
7222
+ name: string;
7223
+ sku: string;
7224
+ type: string;
7225
+ family: string;
7226
+ url: string;
7227
+ finalPrice: number;
7228
+ originalPrice: number;
7229
+ discountPercent: number;
7230
+ }
7231
+ interface JoybirdOptionValue {
7232
+ sku: string;
7233
+ value: string;
7234
+ cover: string | null;
7235
+ color: string | null;
7236
+ family: string;
7237
+ tier: number;
7238
+ petFriendly: boolean;
7239
+ performanceFabric: boolean;
7240
+ sustainableFabric: boolean;
7241
+ popular: boolean;
7242
+ }
7243
+ interface JoybirdOption {
7244
+ id: number;
7245
+ name: string;
7246
+ type: string | null;
7247
+ values: JoybirdOptionValue[];
7248
+ }
7249
+ interface JoybirdCatalog {
7250
+ slug: string;
7251
+ name: string;
7252
+ sku: string;
7253
+ type: string;
7254
+ family: string;
7255
+ url: string;
7256
+ dimensions: string;
7257
+ finalPrice: number;
7258
+ originalPrice: number;
7259
+ discountPercent: number;
7260
+ promotionStart: string | null;
7261
+ promotionEnd: string | null;
7262
+ options: JoybirdOption[];
7263
+ }
7264
+ interface JoybirdPriceLine {
7265
+ optionId: number;
7266
+ optionName: string;
7267
+ optionSku: string;
7268
+ valueSku: string;
7269
+ valueName: string;
7270
+ }
7271
+ interface JoybirdPriceResult {
7272
+ slug: string;
7273
+ sku: string;
7274
+ finalPrice: number;
7275
+ originalPrice: number;
7276
+ discountPercent: number;
7277
+ lines: JoybirdPriceLine[];
7278
+ }
7279
+
7280
+ /**
7281
+ * Reads Joybird's real sofa/sectional configurator — every configurable product, every fabric
7282
+ * and wood stain, and the live configured price Joybird's own page shows.
7283
+ */
7284
+ interface Unit {
7285
+ /**
7286
+ * Lists every configurable product Joybird sells — sofas, sectionals, chairs, ottomans, beds,
7287
+ * organised by collection — with its slug, name, current displayed price, list price and
7288
+ * active discount. Takes nothing. The slug it returns is what getConfigurator and
7289
+ * priceConfigurator take.
7290
+ */
7291
+ listConfigurators(): Promise<JoybirdConfigurator[]>;
7292
+
7293
+ /**
7294
+ * Reads one product's full configurator — its dimensions, current price, active promotion
7295
+ * window, and every option slot the product exposes (Fabric, Wood Stain, Orientation, ...)
7296
+ * with the site's full swatch list for each. The slot ids and swatch SKUs it returns are what
7297
+ * priceConfigurator takes.
7298
+ */
7299
+ getConfigurator(slug: string): Promise<JoybirdCatalog>;
7300
+
7301
+ /**
7302
+ * Prices an exact configuration for one product given the caller's swatch picks (one swatch
7303
+ * SKU per slot id; any slot left out uses its first available swatch as a documented default).
7304
+ * Returns the real live total Joybird's own page shows, plus a per-slot breakdown of what was
7305
+ * picked.
7306
+ */
7307
+ priceConfigurator(slug: string, selections: Record<string, string>): Promise<JoybirdPriceResult>;
7308
+ }
7309
+ }
7310
+
5982
7311
  declare namespace BowmarkProvider_kayak {
5983
7312
  // ── Kayak — the unit's own declarations, verbatim ──
5984
7313
  interface KayakQuery {
@@ -6134,6 +7463,17 @@ interface LabcorpTestSummary {
6134
7463
  currency: string; // "USD"
6135
7464
  }
6136
7465
 
7466
+ interface LabcorpTestDetail extends LabcorpTestSummary {
7467
+ sampleType: string; // "Blood & Urine", "Nasal Swab"
7468
+ collectionMethod: string; // "In person at a Labcorp location"
7469
+ turnaroundTime: string; // "1-2 days from when your sample arrives at our lab"
7470
+ ageRange: string; // "18-100", "" if absent
7471
+ metaDescription: string;
7472
+ metaTitle: string;
7473
+ shortDescriptionHtml: string;
7474
+ descriptionHtml: string;
7475
+ }
7476
+
6137
7477
  /** Lab test pricing, PSC location lookup and appointment availability from Labcorp. */
6138
7478
  interface Unit {
6139
7479
  /**
@@ -6142,6 +7482,14 @@ interface LabcorpTestSummary {
6142
7482
  * No doctor's visit required to order.
6143
7483
  */
6144
7484
  search(query: string): Promise<LabcorpTestSummary[]>;
7485
+
7486
+ /**
7487
+ * Returns the full OnDemand test detail for one sku — price, descriptions, sample type,
7488
+ * collection method, turnaround time and acceptable age band. Combines the catalog row
7489
+ * (GraphQL) with the specimen/turnaround facts the site renders on the PDP HTML. Pass the sku
7490
+ * returned by `search`.
7491
+ */
7492
+ getTest(sku: string): Promise<LabcorpTestDetail>;
6145
7493
  }
6146
7494
  }
6147
7495
 
@@ -7441,6 +8789,96 @@ interface medicareMedigapSearch {
7441
8789
  planTypes: medicareMedigapPlanType[];
7442
8790
  }
7443
8791
 
8792
+ interface medicarePlanDetail {
8793
+ /** CMS's contract-plan-segment triple joined by '-', e.g. "S5884-103-0". */
8794
+ id: string;
8795
+ name: string;
8796
+ nameSpanish: string | null;
8797
+ organization: string;
8798
+ contractId: string;
8799
+ planId: string;
8800
+ segmentId: string;
8801
+ year: number;
8802
+ /** CMS's own category string: "Medicare Advantage" / "Medicare Advantage with
8803
+ * Prescription Drug Coverage" / "Medicare Prescription Drug Plan" /
8804
+ * "Special Needs Plan". */
8805
+ category: string;
8806
+ planType: "PLAN_TYPE_PDP" | "PLAN_TYPE_MA" | "PLAN_TYPE_MAPD" | "PLAN_TYPE_SNP";
8807
+ carrierUrl: string | null;
8808
+ contractYear: string;
8809
+ partcPremium: number;
8810
+ partdPremium: number;
8811
+ partbPremiumReduction: number;
8812
+ /** Annual drug deductible in dollars; 0 means none. PDP only. */
8813
+ drugPlanDeductible: number | null;
8814
+ /** Annual in-network OOP maximum, verbatim. Empty when not published. */
8815
+ maximumOopc: string;
8816
+ /** Per-visit cost strings, verbatim. Empty when CMS publishes no figure —
8817
+ * "$0" (a real benefit) and "" (not published) are deliberately distinct. */
8818
+ primaryDoctorVisitCost: string;
8819
+ specialistDoctorVisitCost: string;
8820
+ emergencyCareCost: string;
8821
+ /** MA/MAPD only — null on PDP, which has no primary/specialist visits. */
8822
+ primaryDoctorCostSharing: string | null;
8823
+ specialistDoctorCostSharing: string | null;
8824
+ /** 1-5 in half steps, or null when CMS publishes none (with starRatingNote
8825
+ * naming the reason — e.g. "too new to be rated"). */
8826
+ starRating: number | null;
8827
+ starRatingNote: string | null;
8828
+ lowPerforming: boolean;
8829
+ highPerforming: boolean;
8830
+ /** All false on a PDP — supplemental benefits live on the Part C side. */
8831
+ supplementalBenefits: {
8832
+ silverSneakers: boolean;
8833
+ transportation: boolean;
8834
+ telehealth: boolean;
8835
+ otcDrugs: boolean;
8836
+ homeSafetyDevices: boolean;
8837
+ inHomeSupport: boolean;
8838
+ supportForCaregivers: boolean;
8839
+ healthEducation: boolean;
8840
+ counselingServices: boolean;
8841
+ emergencyResponseDevice: boolean;
8842
+ worldwideEmergency: boolean;
8843
+ };
8844
+ providerCoverage: {
8845
+ /** False on plans with no network (e.g. PFFS); providers is then reliably empty. */
8846
+ hasProviderCoverageData: boolean;
8847
+ providerCount: number;
8848
+ };
8849
+ /** Extra Help / Low-Income Subsidy dollar amounts at each LIS band. */
8850
+ lis: {
8851
+ level100: number;
8852
+ level75: number;
8853
+ level50: number;
8854
+ level25: number;
8855
+ };
8856
+ snpType: string;
8857
+ dsnpIntegrationLevel: string;
8858
+ /** When CMS marks the plan as terminated for the search year. */
8859
+ terminatedWithoutCrosswalk: string | null;
8860
+ /** Empty when the plan is published in full; the SPA hides fields CMS marks
8861
+ * for redaction and the same fields arrive here. */
8862
+ redactions: string[];
8863
+ }
8864
+
8865
+ interface medicareGetPlanQuery {
8866
+ /** "pdp" | "ma" | "mapd" | "snp" — the caller's MUST match the row they
8867
+ * have in hand. The same (contractId, planId, segmentId) triple does NOT
8868
+ * exist across plan types by design. */
8869
+ planType: "pdp" | "ma" | "mapd" | "snp";
8870
+ /** CMS's contract id (e.g. "S5884" for Part D, "H1234" for Part C). */
8871
+ contractId: string;
8872
+ planId: string;
8873
+ segmentId: string;
8874
+ /** Defaults to the current calendar year — CMS renumbers every January. */
8875
+ year?: number;
8876
+ /** 5-digit US ZIP. Required because the API is keyed on (fips, zip). */
8877
+ zip: string;
8878
+ /** Needed only for the rare ZIP that crosses a state line. */
8879
+ county?: string;
8880
+ }
8881
+
7444
8882
  /**
7445
8883
  * The US government's own Medicare site — Medicare Advantage, Part D and Medigap plan search
7446
8884
  * with real drug-cost estimates, the Care Compare directory of doctors, hospitals, nursing
@@ -7548,6 +8986,26 @@ interface medicareMedigapSearch {
7548
8986
  * walked-radius honesty split `findDoctors` uses, for the identical reason.
7549
8987
  */
7550
8988
  findHospitals(query: medicareHospitalQuery): Promise<medicareHospitalSearch>;
8989
+
8990
+ /**
8991
+ * The full detail of one Part D / MA / MAPD / SNP plan, identified by its CMS
8992
+ * contract-plan-segment triple (e.g. `S5884-103-0` for Part D, `Hxxxx-yyyy-0` for Part C).
8993
+ * Returns the per-visit and per-event cost strings verbatim ('$0', '$20 copay', '20%', or
8994
+ * empty when CMS publishes none), the annual in-network OOP maximum, the supplemental benefits
8995
+ * (dental, fitness, telehealth, OTC drugs, transportation, worldwide emergency — PDPs set them
8996
+ * all to false because the supplemental benefit half is a Part C thing), the CMS star rating
8997
+ * with the explicit reason when none is published (e.g. 'too new to be rated' rather than
8998
+ * rendering a null as a middling rating), the Extra Help / LIS dollar amounts at each band,
8999
+ * the provider-coverage summary, and the carrier's own CMS-published page. `planType` must be
9000
+ * the same discriminator `searchDrugPlans` / a future health-plan search used to find the
9001
+ * triple — the same `(contractId, planId, segmentId)` does NOT exist across plan types by
9002
+ * design, so the wrong one throws. `zip` is required because the API is keyed on (fips, zip),
9003
+ * not on the plan id alone — without it there is no region to ask about. `year` defaults to
9004
+ * the current calendar year. NOTE: the per-visit cost strings are verbatim and the difference
9005
+ * between '$0' (a real zero-cost benefit) and '' (not published) is load-bearing — never
9006
+ * coerce an empty string to 0.
9007
+ */
9008
+ getPlan(arg0: medicareGetPlanQuery): Promise<medicarePlanDetail>;
7551
9009
  }
7552
9010
  }
7553
9011
 
@@ -8472,6 +9930,85 @@ interface ottoSearchQuery {
8472
9930
  }
8473
9931
  }
8474
9932
 
9933
+ declare namespace BowmarkProvider_paypal {
9934
+ // ── PayPal — the unit's own declarations, verbatim ──
9935
+ interface PaypalEstimateFeeArgs {
9936
+ amount: number; // > 0, in `currency`
9937
+ currency: string; // ISO 4217, e.g. "USD"
9938
+ crossBorder: boolean; // sender and recipient in different countries
9939
+ fundingSource: "balance" | "bank" | "card" | "amexSend";
9940
+ }
9941
+ interface PaypalFeeCitation {
9942
+ documentId: string; // the CMS fee-table id this figure came from, e.g. "FEETB20"
9943
+ feeDataKey: string; // the exact published value used, e.g. "2.90%"
9944
+ internalName: string;
9945
+ }
9946
+ interface PaypalFeeEstimate {
9947
+ amount: number;
9948
+ currency: string;
9949
+ crossBorder: boolean;
9950
+ fundingSource: "balance" | "bank" | "card" | "amexSend";
9951
+ fee: number;
9952
+ net: number; // amount - fee
9953
+ citations: PaypalFeeCitation[];
9954
+ }
9955
+ interface PaypalGetFeesArgs {
9956
+ audience?: "consumer"; // defaults to "consumer"; merchant is a separate, unverified page
9957
+ country?: string; // ISO 3166-1 alpha-2, defaults to "us"; only "us" is verified end-to-end
9958
+ }
9959
+ interface PaypalFeeToken {
9960
+ feeDataKey: string; // the exact published value, e.g. "2.90%" or "0.30 USD"
9961
+ internalName: string;
9962
+ percent: number | null; // 0.029 when "2.90%", else null
9963
+ amount: { amount: number; currency: string } | null; // when "0.30 USD", else null
9964
+ }
9965
+ interface PaypalFeeRow {
9966
+ labels: string[]; // plain-text label cells, in cell order
9967
+ tokens: PaypalFeeToken[]; // every published fee token on the row, across all columns
9968
+ cells: string[]; // plain-text rendering of each cell, in cell order
9969
+ noFee: boolean; // true iff the row carries no fee token (PayPal's "No fee" rows)
9970
+ citations: PaypalFeeCitation[];
9971
+ }
9972
+ interface PaypalFeeTable {
9973
+ documentId: string; // the CMS fee-table id, e.g. "FEETB20"
9974
+ caption: string; // PayPal's own caption, e.g. "Sending domestic personal transactions"
9975
+ rows: PaypalFeeRow[];
9976
+ }
9977
+ interface PaypalFeeSchedule {
9978
+ audience: "consumer";
9979
+ country: string; // lowercased to match PayPal's URL path, e.g. "us"
9980
+ sourceUrl: string;
9981
+ tables: PaypalFeeTable[];
9982
+ }
9983
+
9984
+ /**
9985
+ * PayPal's public, signed-out surfaces: the published consumer and merchant fee schedules, the
9986
+ * fee on one concrete personal (friends-and-family) transaction, currency-conversion quotes
9987
+ * and the spread PayPal adds, Pay Later instalment plans, PayPal.Me handle lookup, Help Center
9988
+ * search and articles, the binding policy documents, PayPal Shopping cashback offers, crypto
9989
+ * prices, and invoice payer-view reads. Two functions callable today — estimateFee, getFees.
9990
+ */
9991
+ interface Unit {
9992
+ /**
9993
+ * Computes what PayPal charges to send a PERSONAL (friends-and-family) payment — domestic or
9994
+ * cross-border, by funding source — off PayPal's own published fee schedule, e.g.
9995
+ * estimateFee({ amount: 100, currency: "USD", crossBorder: false, fundingSource: "card" }) ->
9996
+ * { fee: 3.2, net: 96.8, citations: [...] }. Does not (yet) cover goods-and-services/merchant
9997
+ * transactions, a separate page nobody has walked.
9998
+ */
9999
+ estimateFee(args: PaypalEstimateFeeArgs): Promise<PaypalFeeEstimate>;
10000
+
10001
+ /**
10002
+ * Reads PayPal's published fee schedule for one audience / country pair and returns every fee
10003
+ * table on the page — every row, every published feeDataKey, with documentId-level citations —
10004
+ * so a caller can inspect the schedule itself rather than asking about one amount. Currently
10005
+ * consumer / us only; merchant is on a separate unverified page and other countries have not
10006
+ * been fetched.
10007
+ */
10008
+ getFees(args: PaypalGetFeesArgs): Promise<PaypalFeeSchedule>;
10009
+ }
10010
+ }
10011
+
8475
10012
  declare namespace BowmarkProvider_pirateship {
8476
10013
  // ── Pirate Ship — the unit's own declarations, verbatim ──
8477
10014
  interface PirateshipDimensions {
@@ -8646,23 +10183,106 @@ interface PizzahutMenuItemModifier {
8646
10183
  weights: PizzahutMenuItemWeight[]; // portion/intensity choices for this modifier
8647
10184
  }
8648
10185
 
8649
- interface PizzahutMenuItemWeight {
8650
- modifierWeightCode: string; // pass slotCode + modifierCode + this to priceOrder's modifiers
8651
- name: string | null; // e.g. "Light", "Regular", "Extra"
8652
- priceCents: number; // what THIS option costs on THIS variant — varies by size
10186
+ interface PizzahutMenuItemWeight {
10187
+ modifierWeightCode: string; // pass slotCode + modifierCode + this to priceOrder's modifiers
10188
+ name: string | null; // e.g. "Light", "Regular", "Extra"
10189
+ priceCents: number; // what THIS option costs on THIS variant — varies by size
10190
+ }
10191
+
10192
+ // ── getMenu ───────────────────────────────────────────────────────────────
10193
+ interface PizzahutMenuArgs {
10194
+ storeNumber: string;
10195
+ }
10196
+
10197
+ interface PizzahutMenuVariant {
10198
+ variantCode: string;
10199
+ name: string | null;
10200
+ priceCents: number;
10201
+ attributes: string[]; // e.g. ["Original Pan® Pizza", "Personal Pan"]
10202
+ }
10203
+
10204
+ interface PizzahutMenuListItem {
10205
+ productCode: string;
10206
+ name: string | null;
10207
+ description: string | null;
10208
+ categoryCode: string;
10209
+ categoryName: string;
10210
+ currency: string;
10211
+ variants: PizzahutMenuVariant[];
10212
+ }
10213
+
10214
+ interface PizzahutMenuCategory {
10215
+ categoryCode: string;
10216
+ categoryName: string;
10217
+ items: PizzahutMenuListItem[];
10218
+ }
10219
+
10220
+ interface PizzahutMenu {
10221
+ storeNumber: string;
10222
+ currency: string;
10223
+ categories: PizzahutMenuCategory[];
10224
+ }
10225
+
10226
+ // ── getDeals ──────────────────────────────────────────────────────────────
10227
+ // Mirrors the public types declared at the top of this file (PizzahutDeals,
10228
+ // PizzahutDeal, PizzahutDealImage, PizzahutDealScope) — copied here so the
10229
+ // rendered get_library blurb and the catalog signature are types the
10230
+ // gateway can resolve. The exported shapes are the source of truth.
10231
+ type PizzahutDealScopeForRender = "all" | { storeNumbers: string[] };
10232
+
10233
+ interface PizzahutDealImageForRender {
10234
+ url: string;
10235
+ title: string | null;
10236
+ }
10237
+
10238
+ interface PizzahutDealForRender {
10239
+ position: number | null;
10240
+ code: string;
10241
+ name: string;
10242
+ description: string | null;
10243
+ legalText: string | null;
10244
+ appImage: PizzahutDealImageForRender | null;
10245
+ webImage: PizzahutDealImageForRender | null;
10246
+ }
10247
+
10248
+ interface PizzahutDealsForRender {
10249
+ storeNumber: string;
10250
+ deals: PizzahutDealForRender[];
10251
+ sources: { name: string; scope: PizzahutDealScopeForRender }[];
8653
10252
  }
8654
10253
 
8655
10254
  /**
8656
10255
  * Pizza Hut's US ordering site. `findStores` returns the stores serving any US address or ZIP,
8657
10256
  * nearest first, with each one's number, hours, distance, phone and the terms of the carryout
8658
- * and delivery it offers. `getMenuItem` reads one item's full store-level configuration by
8659
- * name every size/crust, and every optional topping/sauce/cheese slot with what each choice
8660
- * costs on THAT variant. `priceOrder` then prices a basket at one of those stores WITHOUT
8661
- * placing it line items, subtotal, sales tax, delivery fee and the real total Pizza Hut
8662
- * would charge, for carryout or to a delivery address, anonymously. Browsing the full menu
8663
- * list and reading the current deals are still stubs.
10257
+ * and delivery it offers. `getMenu` reads a store's whole menu every category, every item,
10258
+ * and every variant's price at THAT store. `getMenuItem` reads one item's full store-level
10259
+ * configuration by name every size/crust, and every optional topping/sauce/cheese slot with
10260
+ * what each choice costs on THAT variant. `getDeals` reads the deals and bundle offers Pizza
10261
+ * Hut is running AT ONE STORE right now, filtered to what is actually redeemable there.
10262
+ * `priceOrder` then prices a basket at one of those stores WITHOUT placing it — line items,
10263
+ * subtotal, sales tax, delivery fee and the real total Pizza Hut would charge, for carryout or
10264
+ * to a delivery address, anonymously.
8664
10265
  */
8665
10266
  interface Unit {
10267
+ /**
10268
+ * Reads a store's whole menu — every category (pizza, wings, pasta, sides, desserts, drinks,
10269
+ * dips, melts, …), every item in each, and each item's variants with their price AT THAT
10270
+ * STORE, all in cents. `storeNumber` comes from `findStores` and is required because Pizza
10271
+ * Hut's prices are store-level — measured 2026-08-07, the same Pepperoni Pizza was $5.50 /
10272
+ * $20.08 at store 026196 (North Hollywood CA) and $6.69 / $12.99 at store 027278 (Plano TX),
10273
+ * all 11 variants differing between the two, so omitting the store would silently return
10274
+ * whatever default the site happens to serve. One GraphQL read returns the whole menu in a
10275
+ * single ~200 KB response (measured 2026-08-07 on store 026196: 20 categories, 138 items, 731
10276
+ * variants, 731/731 with prices), so no fan-out is needed. Bundle items and bare-variant
10277
+ * category items are out of scope — they are not configurable products — same exclusion as
10278
+ * `flattenProductCatalog`. A variant is the priced configuration (size + crust already in
10279
+ * `variantCode`), so a `variantCode` read here plus a `slotCode` / `modifierCode` /
10280
+ * `modifierWeightCode` triple from `getMenuItem` is everything `priceOrder` needs to price a
10281
+ * configured basket. Wholly anonymous: no account, no session, no identity of any kind, same
10282
+ * guest-token read `priceOrder` and `getMenuItem` use.
10283
+ */
10284
+ getMenu(args: { storeNumber: string }): Promise<PizzahutMenu>;
10285
+
8666
10286
  /**
8667
10287
  * Finds the Pizza Hut stores that serve a US location — each store's number, street address,
8668
10288
  * phone, opening hours, straight-line distance, online status, and the terms of every
@@ -8730,6 +10350,26 @@ interface PizzahutMenuItemWeight {
8730
10350
  * identifying.
8731
10351
  */
8732
10352
  getMenuItem(args: { storeNumber: string; item: string; category?: string }): Promise<PizzahutMenuItem>;
10353
+
10354
+ /**
10355
+ * Reads the deals, coupons and bundle offers Pizza Hut is running AT ONE STORE right now —
10356
+ * every deal that applies there, its bundle code, display name, description and legal text, in
10357
+ * the order the site puts them on the deals page. `storeNumber` comes from `findStores` and is
10358
+ * REQUIRED: Pizza Hut runs national deals AND franchise-local ones, and a deal listed but not
10359
+ * available at the caller's store is the honest-vs-misleading line — the function filters by
10360
+ * `MenuDealPageSortOverride.storesList` (a comma-separated list of stores, or the literal
10361
+ * "ALL") so a caller gets only what is actually redeemable where they asked. The store's deals
10362
+ * page lives on Contentful (NOT the Yum storefront GraphQL the rest of the provider hits): the
10363
+ * deals page's own `__NEXT_DATA__.runtimeConfig` publishes `CONTENTFUL_SPACE_ID` +
10364
+ * `CONTENTFUL_ACCESS_TOKEN` + `CONTENTFUL_ENVIRONMENT` + `CONTENTFUL_BASE_URL`, and this reads
10365
+ * them out of the page rather than asking the caller for them. The bootstrap throws on a
10366
+ * missing payload the way `parsePhdConfig` does — a 200 without the runtimeConfig is the
10367
+ * Canadian site, and serving a caller the wrong country’s deals is worse than no answer. The
10368
+ * list is sorted by `dealPagePosition` (1-based, lower = higher up); positions the site leaves
10369
+ * null fall back to a stable code-order tiebreak rather than being treated as "first". Wholly
10370
+ * anonymous, one Contentful read per call.
10371
+ */
10372
+ getDeals(args: { storeNumber: string }): Promise<PizzahutDealsForRender>;
8733
10373
  }
8734
10374
  }
8735
10375
 
@@ -9975,6 +11615,38 @@ interface SearsProduct {
9975
11615
  description: string | null;
9976
11616
  specifications: SearsProductSpecification[];
9977
11617
  }
11618
+ interface SearsShippingAvailability {
11619
+ available: boolean;
11620
+ availableQuantity: number | null;
11621
+ ffmType: string | null;
11622
+ shipModes: string[];
11623
+ dcUnitId: string | null;
11624
+ promiseDate: string | null;
11625
+ autoUpgrade: boolean;
11626
+ freeShipping: boolean;
11627
+ freeEligible: boolean;
11628
+ freeQualified: boolean;
11629
+ }
11630
+ interface SearsStockStore {
11631
+ unitId: string | null;
11632
+ storeName: string | null;
11633
+ storeBrand: string | null;
11634
+ storeAddress: string | null;
11635
+ promiseDate: string | null;
11636
+ ffmType: string | null;
11637
+ }
11638
+ interface SearsPickupAvailability {
11639
+ available: boolean;
11640
+ stores: SearsStockStore[];
11641
+ message: string | null;
11642
+ }
11643
+ interface SearsStock {
11644
+ productId: string;
11645
+ zipCode: string;
11646
+ quantity: number;
11647
+ shipping: SearsShippingAvailability | null;
11648
+ pickup: SearsPickupAvailability;
11649
+ }
9978
11650
 
9979
11651
  /** Sears' own storefront — product search, product detail, fulfillment/stock and store locator. */
9980
11652
  interface Unit {
@@ -9998,6 +11670,18 @@ interface SearsProduct {
9998
11670
  * default (New York, 10101). THROWS on an id the site does not recognise.
9999
11671
  */
10000
11672
  getProduct(idOrUrl: string, opts?: { zipCode?: string }): Promise<SearsProduct>;
11673
+
11674
+ /**
11675
+ * Answers whether a Sears product is buyable right now — for shipping/delivery AND for
11676
+ * in-store/curbside pickup — the way the product page's own fulfillment panel does, in one
11677
+ * call. `shipping` carries the site's own available quantity, ship modes and promise date.
11678
+ * `pickup.stores` is the stores the site found able to fulfil it near `zipCode` — routinely
11679
+ * empty (Sears' physical footprint has shrunk sharply), which is a real, common answer, not an
11680
+ * error; `pickup.message` carries the site's own explanation when it is. `zipCode` narrows the
11681
+ * search the way the site's own zip cookie does; omit it for the site's own default (New York,
11682
+ * 10101). Takes the product id or URL from `search`/`getProduct` — same as `getProduct`.
11683
+ */
11684
+ checkStock(idOrUrl: string, opts?: { zipCode?: string; quantity?: number }): Promise<SearsStock>;
10001
11685
  }
10002
11686
  }
10003
11687
 
@@ -10592,6 +12276,198 @@ interface StatefarmBusinessCoverage {
10592
12276
  }
10593
12277
  }
10594
12278
 
12279
+ declare namespace BowmarkProvider_stickergiant {
12280
+ // ── StickerGiant — the unit's own declarations, verbatim ──
12281
+ // StickerGiant's OWN shape — not a capability contract.
12282
+
12283
+ interface StickergiantListArgs {
12284
+ format?: string; // optional material code filter, e.g. "WHP"
12285
+ }
12286
+
12287
+ interface StickergiantProduct {
12288
+ url: string; // The configurator's own entry URL — durable key
12289
+ name: string; // "Individual Stickers (Die Cut) - White"
12290
+ sku: string; // The site's own material code, e.g. "WHP"
12291
+ priceUsd: string; // "$37.90" — per-100 stickers starting price
12292
+ priceValue: number; // Same number unformatted
12293
+ priceCurrency: string; // "USD"
12294
+ availability: string; // Schema.org URL, e.g. "https://schema.org/InStock"
12295
+ imageUrl: string;
12296
+ }
12297
+
12298
+ interface StickergiantBuild {
12299
+ widthInches: number; // required, from SITE_SIZES
12300
+ heightInches: number; // required, from SITE_SIZES
12301
+ lamination: "OGL" | "MAL"; // required — Outdoor Gloss / Matte
12302
+ quantity?: number; // optional — omit for the full 15-tier ladder back
12303
+ }
12304
+
12305
+ interface StickergiantQuantityPrice {
12306
+ quantity: number;
12307
+ price: number; // the pricing engine's own total (not the rendered 'Total')
12308
+ pricePerUnit: number;
12309
+ }
12310
+
12311
+ interface StickergiantPriceResult {
12312
+ selections: { // echoes back what the engine actually priced
12313
+ widthInches: number;
12314
+ heightInches: number;
12315
+ lamination: "OGL" | "MAL";
12316
+ product: string; // "DCU" — the only product the API honors
12317
+ material: string; // "WHP" — the only material the API honors
12318
+ };
12319
+ selectedQuantity?: StickergiantQuantityPrice; // when caller passed quantity
12320
+ quantityPrices: StickergiantQuantityPrice[]; // always: the full 15-tier ladder
12321
+ }
12322
+
12323
+ /**
12324
+ * StickerGiant's sticker configurator and its published catalog — every sticker SKU on
12325
+ * /custom-stickers with its real starting price, material code and configurator entry URL.
12326
+ */
12327
+ interface Unit {
12328
+ /**
12329
+ * Lists every sticker SKU the /custom-stickers page publishes — name, the configurator's
12330
+ * material URL, the site's own material code (sku), the per-100-stickers starting price the
12331
+ * page carries in its schema.org Product block, the price currency, availability, and the
12332
+ * page's hero image. Optional { format } restricts to one material code (e.g. 'WHP' for Die
12333
+ * Cut White). THROWS rather than returning [] when the page carries no schema.org Product
12334
+ * blocks or when the format filter names an unknown code — both are honest failure modes and
12335
+ * an empty array would read as 'StickerGiant sells no stickers', which is the
12336
+ * confident-wrong-answer failure this provider exists to avoid.
12337
+ */
12338
+ listStickerProducts(args?: StickergiantListArgs): Promise<StickergiantProduct[]>;
12339
+
12340
+ /**
12341
+ * Prices one exact custom-sticker build against Sticker Giant's own live pricing backend (POST
12342
+ * prod.pricing-backend.service.stickergiant.com/item) and returns the full 15-tier quantity
12343
+ * ladder — each tier's price and price-per-unit. With a `quantity` passed, the response also
12344
+ * carries a `selectedQuantity` with the priced value for that exact qty. The returned `price`
12345
+ * is the pricing engine's own canonical number (not the rendered 'Total' on the page, which
12346
+ * carries a small UI markup). THROWS on a missing lamination or out-of-range width/height —
12347
+ * both are caller-fixable.
12348
+ */
12349
+ priceCustomSticker(build: StickergiantBuild): Promise<StickergiantPriceResult>;
12350
+ }
12351
+ }
12352
+
12353
+ declare namespace BowmarkProvider_sunhomesaunas {
12354
+ // ── Sun Home Saunas — the unit's own declarations, verbatim ──
12355
+ // Sun Home Saunas' OWN shapes — not a capability contract.
12356
+
12357
+ interface SunHomeSaunasQuizOption {
12358
+ id: string;
12359
+ label: string;
12360
+ }
12361
+
12362
+ interface SunHomeSaunasQuizQuestion {
12363
+ id: string; // pass back as answers[].questionId
12364
+ title: string;
12365
+ type: string; // the site's own node type, e.g. "SIMPLE_MULTI"
12366
+ options: SunHomeSaunasQuizOption[]; // option.id -> answers[].optionIds
12367
+ }
12368
+
12369
+ interface SunHomeSaunasMatch {
12370
+ handle: string; // the key addSaunaToCart takes
12371
+ title: string;
12372
+ price: number; // dollars — real live Shopify price
12373
+ matchScore: number; // e.g. 5
12374
+ matchOutOf: number; // e.g. 5 -> the site's own "5/5 match"
12375
+ }
12376
+
12377
+ interface SunHomeSaunasCartResult {
12378
+ handle: string;
12379
+ title: string;
12380
+ variantId: number;
12381
+ linePrice: number; // dollars, for the quantity added
12382
+ quantity: number;
12383
+ cartItemCount: number; // the live cart's total items AFTER this add
12384
+ cartTotal: number; // dollars — the live cart's total price after this add
12385
+ }
12386
+
12387
+ /**
12388
+ * Sun Home Saunas' real Perfect Product Finder quiz — the site's own 5-question buyer quiz,
12389
+ * its real server-computed ranked product matches with live prices, and a real Shopify cart
12390
+ * write for the winning match — no login, no dealer routing.
12391
+ */
12392
+ interface Unit {
12393
+ /**
12394
+ * Reads Sun Home Saunas' real, live Perfect Product Finder quiz straight off its quiz vendor's
12395
+ * own API — the current 5 questions and every real option, with the real ids
12396
+ * getPersonalizedSaunaMatches() needs to answer them.
12397
+ */
12398
+ getSaunaFinderQuestions(): Promise<SunHomeSaunasQuizQuestion[]>;
12399
+
12400
+ /**
12401
+ * Submits real answers (from getSaunaFinderQuestions()) through the same quiz session flow the
12402
+ * site's own UI uses, and returns the site's own SERVER-COMPUTED ranked product matches with
12403
+ * real live prices and a real match score — the exact personalized result a real buyer would
12404
+ * see, never a guess from general knowledge.
12405
+ */
12406
+ getPersonalizedSaunaMatches(answers: {questionId: string, optionIds: string[]}[]): Promise<SunHomeSaunasMatch[]>;
12407
+
12408
+ /**
12409
+ * Adds one real matched sauna (a handle from getPersonalizedSaunaMatches()) to a real Shopify
12410
+ * cart at Sun Home Saunas' own real live price, and reads the cart back to confirm the write
12411
+ * landed. THROWS if the product is currently out of stock.
12412
+ */
12413
+ addSaunaToCart(handle: string, quantity?: number): Promise<SunHomeSaunasCartResult>;
12414
+ }
12415
+ }
12416
+
12417
+ declare namespace BowmarkProvider_teladoc {
12418
+ // ── Teladoc Health — the unit's own declarations, verbatim ──
12419
+ interface teladocRow {
12420
+ id: string;
12421
+ }
12422
+
12423
+ interface teladocPricingRow {
12424
+ service: string;
12425
+ priceUsd: number;
12426
+ unit: "visit" | "review" | null;
12427
+ href: string | null;
12428
+ }
12429
+
12430
+ interface teladocPricing {
12431
+ source: string;
12432
+ disclaimer: string;
12433
+ services: teladocPricingRow[];
12434
+ }
12435
+
12436
+ interface teladocInsuranceCoverage {
12437
+ source: string;
12438
+ headline: string;
12439
+ headlinePriceUsd: number;
12440
+ services: string[];
12441
+ disclaimer: string;
12442
+ }
12443
+
12444
+ /**
12445
+ * Virtual-care company: searches its public Health Library and self-pay visit pricing. Booking
12446
+ * a visit requires a member login and is out of scope.
12447
+ */
12448
+ interface Unit {
12449
+ /**
12450
+ * Returns Teladoc's published self-pay (no-insurance) visit pricing — the per-visit dollar
12451
+ * amount for each service line (24/7 Urgent Care, Nutrition, Dermatology, Mental Health), the
12452
+ * unit (visit vs review), the page's own eligibility disclaimer, and the source URL. THROWS
12453
+ * when the no-insurance tile renders without a price list (a real re-skin, not a zero-priced
12454
+ * answer).
12455
+ */
12456
+ getPricing(): Promise<teladocPricing>;
12457
+
12458
+ /**
12459
+ * Returns the with-insurance side of /start/no-insurance — the page's own headline figure (a
12460
+ * literal '$0*' on the live page, since the per-plan price lives behind member.teladoc.com and
12461
+ * is out of scope), the services the page promises are 'Included in your coverage*' (Primary
12462
+ * Care, 24/7 Care, Mental Health, And more!), and the same eligibility disclaimer as
12463
+ * `getPricing`. THROWS when the with-insurance tile renders without its service list, so a
12464
+ * re-skin that drops the second tile or rewrites it in a way this parser cannot read surfaces
12465
+ * as an error rather than an empty answer.
12466
+ */
12467
+ getInsurancePricing(): Promise<teladocInsuranceCoverage>;
12468
+ }
12469
+ }
12470
+
10595
12471
  declare namespace BowmarkProvider_tentree {
10596
12472
  // ── tentree — the unit's own declarations, verbatim ──
10597
12473
  interface TentreeVariant {
@@ -10684,6 +12560,82 @@ interface TentreeCart {
10684
12560
  }
10685
12561
  }
10686
12562
 
12563
+ declare namespace BowmarkProvider_therabody {
12564
+ // ── Therabody — the unit's own declarations, verbatim ──
12565
+ interface TherabodyVariant {
12566
+ /** Shopify's numeric variant id as a string. The future addToCart entry. */
12567
+ id: string;
12568
+ /** The variant's own label, e.g. "Default Title". */
12569
+ title: string;
12570
+ /** Decimal string exactly as the store publishes it, e.g. "54998" (cents). */
12571
+ price: string;
12572
+ /** Same scale as price. Null when the product is not on sale. */
12573
+ compareAtPrice: string | null;
12574
+ /** The store's own SKU. Null on a product without one. */
12575
+ sku: string | null;
12576
+ /** Whether the variant is purchasable right now. */
12577
+ available: boolean;
12578
+ options: string[];
12579
+ }
12580
+ interface TherabodyProduct {
12581
+ /** The handle is the only stable identifier across the catalogue. */
12582
+ handle: string;
12583
+ title: string;
12584
+ vendor: string;
12585
+ productType: string;
12586
+ url: string;
12587
+ descriptionHtml: string | null;
12588
+ optionNames: string[];
12589
+ variants: TherabodyVariant[];
12590
+ /**
12591
+ * The store's own price scale per endpoint — see TherabodyVariant.price for
12592
+ * why the two strings may differ. Range keeps the same scale as the input.
12593
+ */
12594
+ priceRange: { min: string; max: string } | null;
12595
+ /** True if ANY variant is purchasable. The "is it in stock?" answer. */
12596
+ inStock: boolean;
12597
+ tags: string[];
12598
+ /** Therabody's own images, in the order the storefront publishes them. */
12599
+ images: string[];
12600
+ }
12601
+ interface TherabodyRecommendation {
12602
+ /** The matching products, in-stock first, then by handle. */
12603
+ products: TherabodyProduct[];
12604
+ /** What the filter DROPPED, in the same register the rest of the library uses. */
12605
+ warnings: string[];
12606
+ }
12607
+
12608
+ /**
12609
+ * Therabody (Theragun) product catalogue — every device, its variants, its prices and what is
12610
+ * in stock — read off the live Shopify storefront.
12611
+ */
12612
+ interface Unit {
12613
+ /**
12614
+ * Reads the live Therabody catalogue as Therabody publishes it — every product, its handle,
12615
+ * title, vendor, description, tags, images and the per-variant price the storefront is quoting
12616
+ * right now. Returns [] on a transport failure (warnings would be on an object envelope; this
12617
+ * is a list). The catalog page is the line and the parse is the unit of work.
12618
+ */
12619
+ listTheragunProducts(opts?: { limit?: number }): Promise<TherabodyProduct[]>;
12620
+
12621
+ /**
12622
+ * Reads one product by its handle — every variant, its exact price, the image the storefront
12623
+ * is showing and whether that specific variant is purchasable right now. Takes the handle
12624
+ * listTheragunProducts returns. THROWS on an unknown handle (the store answers a real 404).
12625
+ */
12626
+ getTheragunProduct(handle: string): Promise<TherabodyProduct>;
12627
+
12628
+ /**
12629
+ * Filters the live catalogue by what a shopper actually needs — device family, audience, and
12630
+ * the features named (percussion, recovery, hot/cold, breath). Returns the matching products
12631
+ * with their real prices, ranked by in-stock first. The storefront does not publish a query or
12632
+ * filter endpoint, so the function is local filtering on the catalogue listTheragunProducts
12633
+ * already returns — the divide is what the function does with the data, not how it gets there.
12634
+ */
12635
+ recommendTheragun(criteria: { audience?: string; features?: string[]; inStockOnly?: boolean }): Promise<TherabodyRecommendation>;
12636
+ }
12637
+ }
12638
+
10687
12639
  declare namespace BowmarkProvider_thezebra {
10688
12640
  // ── The Zebra — the unit's own declarations, verbatim ──
10689
12641
  interface thezebraStateRatesQuery {
@@ -10948,6 +12900,47 @@ interface thezebraRentersQuotes {
10948
12900
  url: string
10949
12901
  }
10950
12902
 
12903
+ interface thezebraAutoDriver {
12904
+ firstName: string
12905
+ lastName: string
12906
+ dob: string // ISO YYYY-MM-DD — carriers rate on the DATE, not on an age
12907
+ email: string
12908
+ }
12909
+
12910
+ interface thezebraAutoVehicle {
12911
+ year: number // 4-digit; a model year The Zebra does not rate THROWS
12912
+ make: string // "Toyota", "Tesla"
12913
+ model: string // "Camry", "Model 3" — a TRIM is not a page
12914
+ }
12915
+
12916
+ interface thezebraAutoQuotesQuery {
12917
+ driver: thezebraAutoDriver
12918
+ vehicle: thezebraAutoVehicle
12919
+ state: string // 2-letter postal code
12920
+ zip: string // 5 digits
12921
+ county: string // the county the ZIP sits in — the gateway validates server-side
12922
+ }
12923
+
12924
+ interface thezebraAutoQuote {
12925
+ carrier: string // e.g. "Progressive"
12926
+ carrierSlug: string // the site's own slug, e.g. "progressive"
12927
+ monthlyPremium: number // USD per MONTH; the card's period is asserted
12928
+ sixMonthPremium: number | null // USD per 6-month policy, where the card publishes one
12929
+ totalPremium: number | null // USD for the whole term, never derived
12930
+ policyLengthMonths: number | null
12931
+ deductible: number | null
12932
+ coverages: string[] // every coverage the card lists, verbatim
12933
+ }
12934
+
12935
+ interface thezebraAutoQuotes {
12936
+ quotes: thezebraAutoQuote[] // cheapest monthly premium first; [] is a real answer
12937
+ // The carriers ADVERTISED beside the quotes — paid placements with no price.
12938
+ // Returned under their own name so they can never be read as offers.
12939
+ advertisedCarriers: string[]
12940
+ warnings: string[] // names every dropped source / what the gateway refused
12941
+ url: string
12942
+ }
12943
+
10951
12944
  /**
10952
12945
  * US insurance comparison marketplace — side-by-side auto, home and renters rates from 100+
10953
12946
  * carriers, plus published rate research by state, city, vehicle, carrier and driver history.
@@ -11121,6 +13114,34 @@ interface thezebraRentersQuotes {
11121
13114
  * homeowners funnel reaches the same results page and publishes no premium anywhere on it.
11122
13115
  */
11123
13116
  getRentersQuotes(query: thezebraRentersQuotesQuery): Promise<thezebraRentersQuotes>;
13117
+
13118
+ /**
13119
+ * Returns REAL auto insurance quotes for one driver and one vehicle at a US ZIP — each
13120
+ * carrier's own monthly and six-month premium, deductible, and the coverage it priced, as The
13121
+ * Zebra's auto quote funnel prices them. This is a priced offer for the person asking, NOT the
13122
+ * published averages `getStateRates` and its siblings return. Pass `driver` (`firstName`,
13123
+ * `lastName`, `dob` ISO YYYY-MM-DD, `email`), one `vehicle` (`year`, `make`, `model` — a model
13124
+ * The Zebra does not rate THROWS naming the URL it tried), the 2-letter `state`, a 5-digit
13125
+ * `zip`, and `county` (the county the ZIP sits in — The Zebra validates it server-side and a
13126
+ * missing or wrong county is bounced). **The write binds, the read does not — yet**: the
13127
+ * GraphQL gateway at `graphql-gateway.production.thezebra.com` accepts the auto seed
13128
+ * (`LegacyStartInput.start.currentlyInsured` is the only field Apollo currently exposes on
13129
+ * that input), but the results route STILL bounces the session to the homepage with the four
13130
+ * fields this function sends. The function throws on the bounce with a message naming the gap;
13131
+ * the second required field on `LegacyStartInput` is the next attempt's work, and the rejected
13132
+ * probes — `helpToday`, `userPurchaseTimeframe`, `hadActiveInsurance`, `residenceOwnership`,
13133
+ * `presumedAnswers`, `policyLinkInfo`, `startDate`, `desiredCoverage` — are documented in
13134
+ * `agents/capability-engineer/instances/vertical-insurance/tools/zebra-auto-quotes/shape-summary.json`
13135
+ * (and the e5 clone) so they don't have to be re-derived. **`advertisedCarriers` is not a
13136
+ * quote list and must never be read as one**: the results page would carry paid carrier
13137
+ * placements alongside real offers, separated by `data-cy="results-card_ad_<carrier>"` (ad)
13138
+ * versus `data-cy="results-card_q2b_<carrier>"` (real offer), and the advertised names are
13139
+ * returned in their own field with no price attached. Every premium is USD and
13140
+ * `monthlyPremium` is per MONTH — the card's own period is checked rather than assumed, and a
13141
+ * card printing any other term THROWS instead of relabelling a figure. `totalPremium` is the
13142
+ * site's own whole-term number and is never divided out of the monthly one.
13143
+ */
13144
+ getAutoQuotes(query: thezebraAutoQuotesQuery): Promise<thezebraAutoQuotes>;
11124
13145
  }
11125
13146
  }
11126
13147
 
@@ -11271,6 +13292,46 @@ interface UlrichPriceResult {
11271
13292
  }
11272
13293
  }
11273
13294
 
13295
+ declare namespace BowmarkProvider_viewrail {
13296
+ // ── Viewrail — the unit's own declarations, verbatim ──
13297
+ interface ViewrailMaterial {
13298
+ slug: string;
13299
+ title: string;
13300
+ metal: boolean;
13301
+ defaultFinish: string | null;
13302
+ finishes: string[];
13303
+ }
13304
+
13305
+ interface ViewrailMountingStyle {
13306
+ slug: string;
13307
+ title: string;
13308
+ availableMaterials: string[];
13309
+ }
13310
+
13311
+ /**
13312
+ * Cable railing / floating-stair manufacturer — the material and mounting-style catalog behind
13313
+ * Victor, Viewrail's own draw-and-quote design app (victor.viewrail.com). listMaterials and
13314
+ * listMountingStyles are live; the rest of Victor's option set (infill, posts, handrails,
13315
+ * newels) are stubs.
13316
+ */
13317
+ interface Unit {
13318
+ /**
13319
+ * Lists the metal and metal-look composite families Victor's cable railing configurator offers
13320
+ * (304/316/2205 stainless steel, aluminum, wood-grain aluminum, …), each with whether it's a
13321
+ * true metal, its default finish, and every finish slug it supports — off Victor's own
13322
+ * materials-config API.
13323
+ */
13324
+ listMaterials(): Promise<ViewrailMaterial[]>;
13325
+
13326
+ /**
13327
+ * Lists Victor's post-mounting styles (Surface Mount, Side Mount, SLIM Side Mount, Bump Out
13328
+ * Side Mount, Core Drill, …) and which material families each is available in — the first
13329
+ * choice Victor's own design flow asks a user to make before drawing a run.
13330
+ */
13331
+ listMountingStyles(): Promise<ViewrailMountingStyle[]>;
13332
+ }
13333
+ }
13334
+
11274
13335
  declare namespace BowmarkProvider_visible {
11275
13336
  // ── Visible — the unit's own declarations, verbatim ──
11276
13337
  interface VisibleDealOffer {
@@ -11375,15 +13436,91 @@ interface VisibleGetPhoneResult {
11375
13436
  flashSale: VisiblePhoneFlashSale | null;
11376
13437
  }
11377
13438
 
13439
+ interface VisibleCoveragePoint {
13440
+ matchedAddress: string | null;
13441
+ city: string | null;
13442
+ state: string | null;
13443
+ zip: string | null;
13444
+ latitude: number;
13445
+ longitude: number;
13446
+ }
13447
+
13448
+ interface VisibleCheckCoverageResult {
13449
+ input: string;
13450
+ point: VisibleCoveragePoint;
13451
+ tier: "5gUltraWideband" | "5gNationwide" | "4gLte" | "none";
13452
+ fiveGUltraWideband: boolean;
13453
+ fiveGNationwide: boolean;
13454
+ fourGLte: boolean;
13455
+ /** The site's own one-word verdict, forwarded verbatim. Measured to disagree
13456
+ * with the tier flags on a real point — trust the flags over this. */
13457
+ summary: string;
13458
+ }
13459
+
13460
+ interface VisibleSearchPhone {
13461
+ slug: string;
13462
+ name: string;
13463
+ make: string;
13464
+ deviceOs: string | null;
13465
+ listPrice: number | null;
13466
+ price: number | null;
13467
+ monthlyPrice: number | null;
13468
+ financingTermMonths: number | null;
13469
+ inStock: boolean;
13470
+ preOwned: boolean;
13471
+ fiveG: boolean;
13472
+ eSIMCompatible: boolean;
13473
+ comingSoon: boolean;
13474
+ tradeInEligible: boolean;
13475
+ visiblePaybackEligible: boolean | null;
13476
+ imageUrl: string | null;
13477
+ source: string;
13478
+ flashSale: VisiblePhoneFlashSale | null;
13479
+ }
13480
+
13481
+ interface VisibleSearchPhonesResult {
13482
+ source: string;
13483
+ totalCatalogueCount: number;
13484
+ filteredCount: number;
13485
+ page: number;
13486
+ pageSize: number;
13487
+ hasMore: boolean;
13488
+ availableMakes: string[];
13489
+ results: VisibleSearchPhone[];
13490
+ }
13491
+ interface VisiblePlanFeature {
13492
+ label: string | null;
13493
+ items: string[];
13494
+ }
13495
+ interface VisiblePlan {
13496
+ name: string;
13497
+ monthlyPrice: number;
13498
+ regularPrice: number | null;
13499
+ promoCode: string | null;
13500
+ promoText: string | null;
13501
+ taxesAndFeesIncluded: boolean | null;
13502
+ badge: string | null;
13503
+ ctaCode: string | null;
13504
+ ctaUrl: string | null;
13505
+ features: VisiblePlanFeature[];
13506
+ }
13507
+ interface VisibleGetPlansResult {
13508
+ source: string;
13509
+ plans: VisiblePlan[];
13510
+ }
13511
+
11378
13512
  /**
11379
13513
  * Visible (Verizon's prepaid brand): the promotions running right now — the offer grid with
11380
13514
  * its promo codes and fine print, plus the standing referral, trade-in, payback, Stack'em and
11381
- * Fios home-internet bundle programmes — and one phone in full from its catalogue slug or URL,
13515
+ * Fios home-internet bundle programmes — one phone in full from its catalogue slug or URL,
11382
13516
  * every storage/colour SKU with its own price, monthly financing terms and live stock,
11383
- * alongside the specs, images, device-protection plans and eSIM/5G support. Also declared, not
11384
- * yet built: plan pricing, network coverage by address, bring-your-own-device compatibility,
11385
- * phone SEARCH across the catalogue, per-device trade-in values, international rates, the
11386
- * wearable catalogue and the support estate.
13517
+ * alongside the specs, images, device-protection plans and eSIM/5G support Verizon's real
13518
+ * network coverage at a caller-supplied US address or ZIP, broken down by 5G Ultra Wideband /
13519
+ * 5G Nationwide / 4G LTE rather than a single yes/no — and the three-tier line-up as the plans
13520
+ * page renders it, with each tier's headline price, the running promo and the code that
13521
+ * unlocks it, the marketing badge and the four labelled feature sections. Also declared, not
13522
+ * yet built: bring-your-own-device compatibility, per-device trade-in values, international
13523
+ * rates, the wearable catalogue and the support estate.
11387
13524
  */
11388
13525
  interface Unit {
11389
13526
  /**
@@ -11409,6 +13546,48 @@ interface VisibleGetPhoneResult {
11409
13546
  * that ended months ago.
11410
13547
  */
11411
13548
  getPhone(slugOrUrl: string, options?: { preOwned?: boolean }): Promise<VisibleGetPhoneResult>;
13549
+
13550
+ /**
13551
+ * Returns the phones Visible currently sells, with the headline facts a purchase turns on —
13552
+ * name, make, OS, list price, current price, financed monthly payment and term, in-stock
13553
+ * status, pre-owned vs new, 5G support, eSIM compatibility, trade-in / Payback eligibility,
13554
+ * and the catalogue image. Optional filters narrow by make (Apple, Samsung, Google, Motorola,
13555
+ * TCL), by a `priceMax` the buyer's actually-going-to-pay price (NOT the strikethrough on a
13556
+ * stale flash-sale banner), by 5G support, and by in-stock availability. Pagination is
13557
+ * explicit and client-side over the catalogue's bounded 42-row response — the endpoint does
13558
+ * NOT paginate server-side; every tried pagination parameter is ignored. Joins naturally with
13559
+ * `getPhone`, which takes the same `slug` as its input — `searchPhones` answers "what does
13560
+ * Visible sell?", `getPhone` answers "what does this specific device cost across storage and
13561
+ * colour?".
13562
+ */
13563
+ searchPhones(options?: { make?: string; priceMax?: number; supports5G?: boolean; inStock?: boolean; page?: number; pageSize?: number }): Promise<VisibleSearchPhonesResult>;
13564
+
13565
+ /**
13566
+ * Returns Verizon's real network coverage — the tier that actually determines usable speed (5G
13567
+ * Ultra Wideband, 5G Nationwide, or 4G LTE) — at a caller-supplied US street address or
13568
+ * 5-digit ZIP, straight from the same point-level lookup Verizon's own coverage map (embedded
13569
+ * in visible.com/plans/coverage) queries. Geocodes the input first — a full address via the US
13570
+ * Census Bureau's public geocoder, a bare ZIP via a ZIP-centroid lookup — then reads the tiers
13571
+ * at that exact point, never a national or per-ZIP summary standing in for an address-level
13572
+ * answer. Also returns the site's own one-word verdict ("Best"/"Good"/"Moderate"/"No
13573
+ * Coverage") as `summary`, measured to sometimes DISAGREE with the tier flags — the flags are
13574
+ * the ones to trust.
13575
+ */
13576
+ checkCoverage(addressOrZip: string): Promise<VisibleCheckCoverageResult>;
13577
+
13578
+ /**
13579
+ * Returns the three tiers Visible sells today (Visible, Visible+, Visible+ Pro) as the plans
13580
+ * page renders them — each tier's headline monthly price, the regular price the running promo
13581
+ * unlocks (e.g. $19/mo with code SAVE6 unlocking $25/mo), the promo code itself, the "Taxes &
13582
+ * fees included" guarantee, the marketing badge ("Most popular" / "Best value" / "Ultimate
13583
+ * experience"), the CTA button code that pre-fills /shop/plan-selected, and four labelled
13584
+ * feature sections (Network, Mobile Hotspot, International, The Extras) with every bullet the
13585
+ * page shows. Reads the LIVE page only, never the site's own /docs/visible_plans.md, which is
13586
+ * dated 2025-11-12 and answers the same prompt with two stale tiers and no code. Three tiers
13587
+ * is hard — a future fourth tier changes the answer visibly rather than reading as a
13588
+ * half-broken response.
13589
+ */
13590
+ getPlans(): Promise<VisibleGetPlansResult>;
11412
13591
  }
11413
13592
  }
11414
13593
 
@@ -11536,6 +13715,27 @@ interface wellfoundCompanyRow {
11536
13715
  highlightedRoles: { id: string; title: string; url: string; locations: string[] }[];
11537
13716
  }
11538
13717
 
13718
+ interface wellfoundCompanyDetail {
13719
+ id: string;
13720
+ name: string;
13721
+ slug: string;
13722
+ url: string;
13723
+ highConcept: string | null;
13724
+ productDescription: string | null;
13725
+ companySize: string | null;
13726
+ employeesMin: number | null;
13727
+ employeesMax: number | null;
13728
+ markets: string[];
13729
+ stage: string | null;
13730
+ activelyHiring: boolean;
13731
+ badges: { id: string; label: string; tooltip: string | null }[];
13732
+ locations: { slug: string; displayName: string }[];
13733
+ remotePolicy: "remote" | null;
13734
+ companyUrl: string | null;
13735
+ totalRaisedAmount: number | null;
13736
+ logoUrl: string | null;
13737
+ }
13738
+
11539
13739
  /**
11540
13740
  * Wellfound (formerly AngelList Talent) — startup job search with salary and equity bands,
11541
13741
  * startup profiles and their open roles.
@@ -11567,6 +13767,15 @@ interface wellfoundCompanyRow {
11567
13767
  * experience-requirement text and the hiring startup.
11568
13768
  */
11569
13769
  getJob(args: { url: string }): Promise<wellfoundJobDetail>;
13770
+
13771
+ /**
13772
+ * Reads one startup's `/company/<slug>` profile — the longer product description (HTML), the
13773
+ * full market tagging, location tags with display names, the explicitly-set Remote policy,
13774
+ * total raised, the company's own website, every badge verbatim, and the same `companySize`
13775
+ * band `searchCompanies` already decodes — the context a candidate weighs a startup on before
13776
+ * applying to it. Takes the `slug` a `searchCompanies` row already carries.
13777
+ */
13778
+ getCompany(args: { slug: string }): Promise<wellfoundCompanyDetail>;
11570
13779
  }
11571
13780
  }
11572
13781
 
@@ -11740,18 +13949,23 @@ interface BowmarkProviders {
11740
13949
  aa: BowmarkProvider_aa.Unit;
11741
13950
  abercrombie: BowmarkProvider_abercrombie.Unit;
11742
13951
  ashleyfurniture: BowmarkProvider_ashleyfurniture.Unit;
13952
+ avis: BowmarkProvider_avis.Unit;
11743
13953
  azure: BowmarkProvider_azure.Unit;
11744
13954
  barletta: BowmarkProvider_barletta.Unit;
11745
13955
  bhphoto: BowmarkProvider_bhphoto.Unit;
11746
13956
  blenderseyewear: BowmarkProvider_blenderseyewear.Unit;
13957
+ bluehaven: BowmarkProvider_bluehaven.Unit;
11747
13958
  bmwusa: BowmarkProvider_bmwusa.Unit;
11748
13959
  cancer: BowmarkProvider_cancer.Unit;
13960
+ caraway: BowmarkProvider_caraway.Unit;
11749
13961
  cars: BowmarkProvider_cars.Unit;
11750
13962
  cheapflights: BowmarkProvider_cheapflights.Unit;
11751
13963
  chriscraft: BowmarkProvider_chriscraft.Unit;
11752
13964
  classpass: BowmarkProvider_classpass.Unit;
11753
13965
  cloudflare: BowmarkProvider_cloudflare.Unit;
13966
+ cyberpowerpc: BowmarkProvider_cyberpowerpc.Unit;
11754
13967
  decked: BowmarkProvider_decked.Unit;
13968
+ dice: BowmarkProvider_dice.Unit;
11755
13969
  dickssportinggoods: BowmarkProvider_dickssportinggoods.Unit;
11756
13970
  dillards: BowmarkProvider_dillards.Unit;
11757
13971
  discounttire: BowmarkProvider_discounttire.Unit;
@@ -11766,11 +13980,13 @@ interface BowmarkProviders {
11766
13980
  grainger: BowmarkProvider_grainger.Unit;
11767
13981
  healthcare_gov: BowmarkProvider_healthcare_gov.Unit;
11768
13982
  hellofresh: BowmarkProvider_hellofresh.Unit;
13983
+ hellotend: BowmarkProvider_hellotend.Unit;
11769
13984
  hilton: BowmarkProvider_hilton.Unit;
11770
13985
  hunter: BowmarkProvider_hunter.Unit;
11771
13986
  ibuypower: BowmarkProvider_ibuypower.Unit;
11772
13987
  insurify: BowmarkProvider_insurify.Unit;
11773
13988
  interiordefine: BowmarkProvider_interiordefine.Unit;
13989
+ joybird: BowmarkProvider_joybird.Unit;
11774
13990
  kayak: BowmarkProvider_kayak.Unit;
11775
13991
  labcorp: BowmarkProvider_labcorp.Unit;
11776
13992
  linkedin: BowmarkProvider_linkedin.Unit;
@@ -11792,6 +14008,7 @@ interface BowmarkProviders {
11792
14008
  newegg: BowmarkProvider_newegg.Unit;
11793
14009
  oanda: BowmarkProvider_oanda.Unit;
11794
14010
  otto: BowmarkProvider_otto.Unit;
14011
+ paypal: BowmarkProvider_paypal.Unit;
11795
14012
  pirateship: BowmarkProvider_pirateship.Unit;
11796
14013
  pizzahut: BowmarkProvider_pizzahut.Unit;
11797
14014
  progressive: BowmarkProvider_progressive.Unit;
@@ -11804,10 +14021,15 @@ interface BowmarkProviders {
11804
14021
  semihandmade: BowmarkProvider_semihandmade.Unit;
11805
14022
  soundcloud: BowmarkProvider_soundcloud.Unit;
11806
14023
  statefarm: BowmarkProvider_statefarm.Unit;
14024
+ stickergiant: BowmarkProvider_stickergiant.Unit;
14025
+ sunhomesaunas: BowmarkProvider_sunhomesaunas.Unit;
14026
+ teladoc: BowmarkProvider_teladoc.Unit;
11807
14027
  tentree: BowmarkProvider_tentree.Unit;
14028
+ therabody: BowmarkProvider_therabody.Unit;
11808
14029
  thezebra: BowmarkProvider_thezebra.Unit;
11809
14030
  trektravel: BowmarkProvider_trektravel.Unit;
11810
14031
  ulrichlifestyle: BowmarkProvider_ulrichlifestyle.Unit;
14032
+ viewrail: BowmarkProvider_viewrail.Unit;
11811
14033
  visible: BowmarkProvider_visible.Unit;
11812
14034
  walmart: BowmarkProvider_walmart.Unit;
11813
14035
  wellfound: BowmarkProvider_wellfound.Unit;
@@ -17278,6 +19500,7 @@ interface BowmarkProviders {
17278
19500
  avedaisland: BowmarkFamily_shopify_store.Unit;
17279
19501
  avenatheme: BowmarkFamily_shopify_store.Unit;
17280
19502
  avenidabresil: BowmarkFamily_shopify_store.Unit;
19503
+ aventon: BowmarkFamily_shopify_store.Unit;
17281
19504
  aventsbyaugust: BowmarkFamily_shopify_store.Unit;
17282
19505
  aventureextension: BowmarkFamily_shopify_store.Unit;
17283
19506
  avenues3: BowmarkFamily_shopify_store.Unit;