@bowmark/web 1.21.0 → 1.22.1

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,8 +5,8 @@
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: 8f74962f532da5df8d2905deb36fe43233b84c4f09f37cb4c76b92a153333d03
9
- // 46 capabilities, 404 providers, 984 typed functions, 20 refused.
8
+ // Manifest version: d7a4e150ac8b92a335cf1f8c899427d12236d7556bd04d8e873ba0729e5a347b
9
+ // 49 capabilities, 416 providers, 1090 typed functions, 20 refused.
10
10
  // 51,715 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
@@ -36,6 +36,125 @@
36
36
 
37
37
 
38
38
 
39
+ declare namespace BowmarkCapability_booking_links {
40
+ // ── Booking links — find a person's Calendly or Cal.com link and read its form — the unit's own declarations, verbatim ──
41
+ type BookingPlatform = "calendly" | "cal.com" | "savvycal" | "tidycal" | "zcal" | "hubspot"
42
+ | "acuity" | "chilipiper" | "google-calendar" | "microsoft-bookings"
43
+
44
+ // published: READ off a page (foundOn is the citation). archived: read off an old
45
+ // Wayback capture of a page (archivedAt dates it). indexed: Google's site:cal.com search for
46
+ // the name returned it (context quotes the result). name_match: built from the name and
47
+ // it exists — nothing shows the person published it, and a namesake can own it.
48
+ type BookingLinkMethod = "published" | "archived" | "indexed" | "name_match"
49
+
50
+ interface BookingLinkFinding {
51
+ url: string
52
+ platform: BookingPlatform
53
+ method: BookingLinkMethod // the strongest way it was found
54
+ foundBy: BookingLinkMethod[] // every way it was found
55
+ foundOn: string | null // the page it was written on
56
+ archivedAt: string | null // YYYY-MM-DD capture date, for "archived"
57
+ archiveUrl: string | null
58
+ context: string | null // the link's anchor text or the words around it
59
+ ownerName: string | null // the name the booking page itself shows (name_match)
60
+ nameConfirmed: boolean // name_match: page owner carries both names; published/archived: the name is on that page
61
+ }
62
+
63
+ interface FindBookingLinksInput {
64
+ name: string // full name, first and last
65
+ company?: string // name or domain — adds "first-company" slugs
66
+ domain?: string // their company site: about/team/contact/services pages + homepage scanned
67
+ github?: string // a handle READ off a page that names them, never guessed
68
+ urls?: string[] // personal site, speaker bio, blog post — any page of theirs
69
+ }
70
+
71
+ interface FindBookingLinksOptions {
72
+ archive?: boolean // read Wayback captures of the domain's about/team/contact pages; default true with a domain
73
+ search?: boolean // Google site:cal.com "<name>" via Serper; default true; each search is charged to your account, or send your own key as the x-bowmark-vendor-key-serper header
74
+ timeoutMs?: number
75
+ }
76
+
77
+ interface BookingLinkSearch {
78
+ name: string
79
+ links: BookingLinkFinding[] // published first, then archived, then name_match
80
+ checked: { pagesScanned: number; pagesUnreachable: string[]; archivedPagesRead: number; slugsChecked: string[] }
81
+ warnings: string[]
82
+ }
83
+
84
+ interface PublishedBookingLink { url: string; platform: BookingPlatform; context: string; nearbyText: string }
85
+ interface PageScan { url: string; finalUrl: string; status: number; links: PublishedBookingLink[]; warnings: string[] }
86
+
87
+ interface BookingQuestion { label: string; kind: string; required: boolean; choices: string[] }
88
+ interface BookingEvent { name: string; url: string; description: string | null; durationMinutes: number | null }
89
+
90
+ interface BookingPage {
91
+ url: string
92
+ platform: "calendly" | "cal.com"
93
+ ownerName: string | null
94
+ organization: string | null // the org/team the platform files the account under (Cal.com)
95
+ avatarUrl: string | null
96
+ events: BookingEvent[] // every event a profile lists
97
+ event: BookingEvent | null // the event whose form was read; null if several and none named
98
+ questions: BookingQuestion[] // everything the form asks
99
+ qualifyingQuestions: string[] // the questions beyond name/email/notes — "company", "team size": a sales funnel asks these, a personal chat does not
100
+ bookable: "open" | "fully_booked" | "closed" | "unknown" // Cal.com is always "unknown" here; use cal_com.getAvailability
101
+ nextAvailability: string | null
102
+ unavailableReason: string | null // the platform's own words when it cannot be booked
103
+ warnings: string[]
104
+ }
105
+
106
+ interface ReadBookingPageOptions { event?: string; timeoutMs?: number }
107
+
108
+ type CallOptions = {
109
+ timeoutMs?: number // per-provider budget in ms, default 30000, clamped to 1000-55000.
110
+ // A provider slower than this is DROPPED from the results and
111
+ // NAMED in warnings — never silently absent
112
+ }
113
+
114
+ /**
115
+ * Finds the public booking link (Calendly, Cal.com, SavvyCal, HubSpot…) a named person
116
+ * publishes — on their company's pages, their GitHub, an old archived copy of their site, or
117
+ * under their own name on Calendly and Cal.com — and reads what the booking form asks and
118
+ * whether the calendar is open, without booking anything.
119
+ */
120
+ interface Unit {
121
+ /**
122
+ * Finds a person's public booking links from their name. Runs four searches at once and merges
123
+ * them, strongest evidence first: links PUBLISHED on their company's
124
+ * about/team/contact/services pages and homepage, their GitHub profile README, the website
125
+ * that profile lists and any `urls` of theirs (each with the page it was on and the words
126
+ * around it); links on ARCHIVED Wayback Machine captures of the company's about/team/contact
127
+ * pages, dated (catches a link since removed); Cal.com pages Google has INDEXED under their
128
+ * name (a `site:cal.com "<name>"` Google search through Serper — each search is charged to
129
+ * your account on Bowmark's key, or send your own as the `x-bowmark-vendor-key-serper` header;
130
+ * if no key can serve it, it is skipped and named in `warnings`); and their name as a slug on
131
+ * Calendly and Cal.com, including "first-company" shapes (NAME_MATCH — exists, but a namesake
132
+ * can own it, so check `ownerName` and tie it to the company). Pass `company` and `domain`
133
+ * whenever known. Google does not index Calendly pages, so the slug check is the only way to
134
+ * find those. Never books.
135
+ */
136
+ find(person: FindBookingLinksInput, options?: FindBookingLinksOptions): Promise<BookingLinkSearch>;
137
+
138
+ /**
139
+ * Lists every booking link written on one page — hrefs, Cal.com embed buttons
140
+ * (`data-cal-link`) and plain-text links — with each link's anchor text and the words around
141
+ * it, ignoring the platforms' own pricing/login/blog pages. Use it on a personal site, a
142
+ * speaker bio or a newsletter footer.
143
+ */
144
+ scanPage(url: string, options?: CallOptions): Promise<PageScan>;
145
+
146
+ /**
147
+ * Reads a Calendly or Cal.com booking page without booking: who owns it, the events it offers,
148
+ * every question its form asks, `qualifyingQuestions` (anything beyond name/email/notes — a
149
+ * sales funnel asks for your company, a personal chat does not), and whether it can be booked
150
+ * (Calendly: open, fully booked, or closed with the platform's own reason). Works on a
151
+ * fully-booked calendar. A profile with several events returns `event: null` and the list
152
+ * unless `options.event` names one (slug or part of the name).
153
+ */
154
+ read(url: string, options?: ReadBookingPageOptions): Promise<BookingPage>;
155
+ }
156
+ }
157
+
39
158
  declare namespace BowmarkCapability_bundles {
40
159
  // ── Check whether a set of products can be built and bought right now — the unit's own declarations, verbatim ──
41
160
  interface BundleItemAvailability {
@@ -291,6 +410,25 @@ type CallOptions = {
291
410
  }
292
411
  }
293
412
 
413
+ declare namespace BowmarkCapability_currency_exchange {
414
+ // ── Currency exchange — the unit's own declarations, verbatim ──
415
+ interface currency_exchangeResult {
416
+ rate: number;
417
+ warnings: string[];
418
+ }
419
+ type CallOptions = {
420
+ timeoutMs?: number // per-provider budget in ms, default 30000, clamped to 1000-55000.
421
+ // A provider slower than this is DROPPED from the results and
422
+ // NAMED in warnings — never silently absent
423
+ }
424
+
425
+ /** Get real-time exchange rates between currencies */
426
+ interface Unit {
427
+ /** Returns the current exchange rate between two currencies */
428
+ getRate(from: string, to: string, options?: CallOptions): Promise<currency_exchangeResult>;
429
+ }
430
+ }
431
+
294
432
  declare namespace BowmarkCapability_custom_sofa_configurator {
295
433
  // ── Custom sofa configurator (fabric selection, live pricing) — the unit's own declarations, verbatim ──
296
434
  type CustomSofa = {
@@ -444,20 +582,14 @@ type CallOptions = {
444
582
  */
445
583
  interface Unit {
446
584
  /**
447
- * Signs up for a real API key on a developer dashboard RUN this, don't just explain how —
448
- * `bowmark.developer_api_key_signup.signUp("alphavantage", { organization: "Acme Corp", email:
449
- * `qa-${Date.now()}@example.com` })`. `service` selects which dashboard (today: "alphavantage"
450
- * only THROWS naming the supported list otherwise, a caller-fixable error).
451
- * `details.organization` and `details.email` are required; when the caller did not supply
452
- * their own, invent placeholder-shaped ones like the example's — the signup is instant and
453
- * unverified, so nothing is lost by not stopping to ask first. MAKE THE EMAIL UNIQUE EVERY
454
- * CALL (e.g. embed `Date.now()`, as the example does) — the dashboard rejects a repeated
455
- * address with "Redundant origin", so a literal copied example email fails on the second and
456
- * every later run. `details.occupation` is optional and dashboard-specific. Returns the real
457
- * key plus the dashboard's own confirmation sentence. `options.timeoutMs` sets the call budget
458
- * (default 30000).
585
+ * Signs up for a real developer API key on a dashboard. `service` selects which dashboard:
586
+ * "alphavantage" for stock data. Supported today: alphavantage THROWS naming the supported
587
+ * list otherwise. Signs up instantly; `details.organization` and `details.email` required
588
+ * (MAKE EMAIL UNIQUE PER CALL, e.g. `qa-${Date.now()}@example.com`, dashboard rejects
589
+ * repeats). `details.occupation` optional. Returns real key plus confirmation.
590
+ * `options.timeoutMs` sets call budget (default 30000).
459
591
  */
460
- signUp(service: string, details: { organization: string, email: string, occupation?: string }, options?: CallOptions): Promise<DeveloperApiKeySignupResult>;
592
+ signUp(service: string, details: object, options?: CallOptions): Promise<DeveloperApiKeySignupResult>;
461
593
  }
462
594
  }
463
595
 
@@ -2500,6 +2632,60 @@ type CallOptions = {
2500
2632
  }
2501
2633
  }
2502
2634
 
2635
+ declare namespace BowmarkCapability_stream_highlights {
2636
+ // ── Stream highlights — cut a highlight of your own live broadcast — the unit's own declarations, verbatim ──
2637
+ interface CreateHighlightOptions {
2638
+ platform?: "twitch" // the default, and the only one today
2639
+ videoId?: string // id or video link; omit for the newest broadcast (the live one, while live)
2640
+ startSeconds: number // seconds into that broadcast
2641
+ endSeconds: number
2642
+ title: string
2643
+ description?: string
2644
+ language?: string // default "en"
2645
+ tags?: string[]
2646
+ game?: string // category name, e.g. "Wetrix"
2647
+ }
2648
+ interface StreamHighlight {
2649
+ // "created" by this call; "existing" = a highlight with this exact title was
2650
+ // already on the channel, nothing new made; "unknown" = no answer came back —
2651
+ // check dashboardUrl. Calling again with the same title is always safe.
2652
+ status: "created" | "existing" | "unknown"
2653
+ platform: "twitch"
2654
+ highlightId: string | null // null only when status is "unknown"
2655
+ url: string | null
2656
+ title: string
2657
+ videoId: string
2658
+ startSeconds: number
2659
+ endSeconds: number
2660
+ channel: string
2661
+ dashboardUrl: string
2662
+ warnings: string[]
2663
+ }
2664
+
2665
+ type CallOptions = {
2666
+ timeoutMs?: number // per-provider budget in ms, default 30000, clamped to 1000-55000.
2667
+ // A provider slower than this is DROPPED from the results and
2668
+ // NAMED in warnings — never silently absent
2669
+ }
2670
+
2671
+ /**
2672
+ * Cuts a permanent Highlight out of a streamer's own broadcast on Twitch — including the one
2673
+ * still live — between two offsets in seconds, with a title. Needs the streamer's Twitch
2674
+ * sign-in: the first run answers needs_user with a link to sign in, and later runs reuse it.
2675
+ */
2676
+ interface Unit {
2677
+ /**
2678
+ * Cuts a highlight from [startSeconds, endSeconds] of the signed-in streamer's broadcast
2679
+ * (`videoId`, or the newest one — the live one while streaming) and titles it. Safe to call
2680
+ * again with the same title: an existing highlight of that title is returned with status
2681
+ * "existing" instead of being cut twice. THROWS with "Retry shortly" when the live broadcast's
2682
+ * archive has not recorded up to endSeconds yet (it trails real time by a minute or two).
2683
+ * Needs a Twitch sign-in.
2684
+ */
2685
+ create(options: CreateHighlightOptions): Promise<StreamHighlight>;
2686
+ }
2687
+ }
2688
+
2503
2689
  declare namespace BowmarkCapability_tariff {
2504
2690
  // ── HS/HTS tariff code lookup — the unit's own declarations, verbatim ──
2505
2691
 
@@ -3717,6 +3903,291 @@ interface AlphavantageSignUpResult {
3717
3903
  }
3718
3904
  }
3719
3905
 
3906
+ declare namespace BowmarkProvider_amazon {
3907
+ // ── Amazon — the unit's own declarations, verbatim ──
3908
+ interface AmazonProduct {
3909
+ asin: string;
3910
+ title: string;
3911
+ url: string;
3912
+ price: number | null;
3913
+ listPrice: number | null;
3914
+ rating: number | null;
3915
+ ratingCount: number | null;
3916
+ sponsored: boolean;
3917
+ }
3918
+ interface SearchProductsArgs {
3919
+ keywords: string;
3920
+ department?: string;
3921
+ sort?: string;
3922
+ priceMin?: number;
3923
+ priceMax?: number;
3924
+ brand?: string;
3925
+ }
3926
+ interface AmazonKeywordSuggestion {
3927
+ value: string;
3928
+ }
3929
+ interface AmazonBestSellerCategory {
3930
+ name: string;
3931
+ slug: string;
3932
+ }
3933
+ interface AmazonBestSellerEntry {
3934
+ asin: string;
3935
+ rank: number;
3936
+ title: string;
3937
+ url: string;
3938
+ price: number | null;
3939
+ rating: number | null;
3940
+ ratingCount: number | null;
3941
+ }
3942
+ interface AmazonBestSellerRankEntry {
3943
+ category: string;
3944
+ rank: number;
3945
+ }
3946
+ interface AmazonProductDetail {
3947
+ asin: string;
3948
+ title: string;
3949
+ url: string;
3950
+ brand: string | null;
3951
+ price: number | null;
3952
+ listPrice: number | null;
3953
+ inStock: boolean;
3954
+ availabilityText: string | null;
3955
+ rating: number | null;
3956
+ ratingCount: number | null;
3957
+ features: string[]; // the site's own free-text bullet points — read them off a result, never guess one from prose
3958
+ specifications: Record<string, string>;
3959
+ breadcrumbs: string[];
3960
+ bestSellersRank: AmazonBestSellerRankEntry[];
3961
+ images: string[];
3962
+ soldBy: string | null;
3963
+ sellerId: string | null;
3964
+ }
3965
+ interface AmazonVariation {
3966
+ asin: string;
3967
+ dimensions: Record<string, string>; // e.g. { style_name: "Skillet", size_name: "12-inch" } — the site's own dimension names
3968
+ isCurrent: boolean;
3969
+ }
3970
+ interface AmazonReview {
3971
+ reviewId: string;
3972
+ author: string;
3973
+ rating: number;
3974
+ title: string;
3975
+ date: string; // the site's own sentence, e.g. "Reviewed in the United States on August 9, 2026"
3976
+ variant: string | null; // e.g. "Style: Skillet, Size: 15-inch"
3977
+ verifiedPurchase: boolean;
3978
+ body: string; // paragraphs joined with a blank line, in the site's own order
3979
+ helpfulCount: number;
3980
+ }
3981
+ interface AmazonRelatedProduct {
3982
+ asin: string;
3983
+ title: string;
3984
+ url: string;
3985
+ price: number | null;
3986
+ rating: number | null; // null on a "Frequently bought together" row — that rail never shows one
3987
+ ratingCount: number | null;
3988
+ }
3989
+ interface AmazonRelatedProducts {
3990
+ boughtTogether: AmazonRelatedProduct[]; // complements, never the current ASIN
3991
+ related: AmazonRelatedProduct[]; // "Customers who viewed this item also viewed" — substitutes
3992
+ unavailableRails: string[]; // sims-consolidated-N_feature_div ids Amazon lazy-loads rather than serving inline
3993
+ }
3994
+ interface AmazonDeal {
3995
+ asin: string;
3996
+ title: string;
3997
+ url: string;
3998
+ dealPrice: number;
3999
+ listPrice: number | null;
4000
+ percentOff: number | null;
4001
+ limitedTimeText: string | null; // e.g. "Limited time deal", or "Ends in 2026-09-16T06:59:59.000Z" for a countdown deal
4002
+ }
4003
+ interface AmazonSellerRatingPeriod {
4004
+ averageRating: number | null;
4005
+ ratingCount: number | null;
4006
+ }
4007
+ interface AmazonSeller {
4008
+ sellerId: string;
4009
+ name: string;
4010
+ positivePercentageLast12Months: number | null; // Amazon's own headline figure; no lifetime equivalent is published
4011
+ ratings: {
4012
+ last30Days: AmazonSellerRatingPeriod;
4013
+ last90Days: AmazonSellerRatingPeriod;
4014
+ last12Months: AmazonSellerRatingPeriod;
4015
+ lifetime: AmazonSellerRatingPeriod;
4016
+ };
4017
+ businessName: string | null;
4018
+ businessAddress: string[];
4019
+ aboutSeller: string | null;
4020
+ }
4021
+ interface GetDeliveryEstimateArgs {
4022
+ product: string;
4023
+ zip: string;
4024
+ }
4025
+ interface AmazonDeliveryEstimate {
4026
+ asin: string;
4027
+ zip: string;
4028
+ zipResolved: boolean; // false = the fields below are Amazon's default location, not this zip
4029
+ deliveryDate: string | null;
4030
+ priceLabel: string | null;
4031
+ condition: string | null; // the site's own labels — read the values off a result, never guess one from prose
4032
+ }
4033
+ interface AmazonSellerOffer {
4034
+ condition: string; // e.g. "New", "Used - Good", "Used - Acceptable" — read the values off a result, never guess one from prose
4035
+ price: number | null;
4036
+ shippingCost: number | null; // derived from shippingLabel ("FREE" -> 0)
4037
+ shippingLabel: string | null; // the site's own delivery-price label, e.g. "FREE" or "$3.99"
4038
+ deliveryEstimate: string | null; // e.g. "September 24 - 29"
4039
+ sellerName: string; // "Amazon.com" when Amazon itself is the seller
4040
+ sellerId: string | null; // null when sold by Amazon.com itself — getSeller's argument otherwise
4041
+ sellerRating: number | null; // 0-5
4042
+ sellerRatingCount: number | null;
4043
+ }
4044
+ interface AmazonSellerOffersResult {
4045
+ asin: string;
4046
+ totalOfferCount: number | null; // Amazon's own count, including offers this page did not render
4047
+ offers: AmazonSellerOffer[]; // page one only, up to 10 — see the note on listSellerOffers
4048
+ }
4049
+
4050
+ /**
4051
+ * Search Amazon's catalogue and read a product the way a shopper does — price, stock, rating,
4052
+ * the customer reviews, the other products it recommends, every size and colour the listing
4053
+ * sells, when it would arrive at a given ZIP — plus the rankings (best sellers, new releases,
4054
+ * movers and shakers, most wished for), today's deals and a marketplace seller's feedback.
4055
+ * searchProducts, suggestKeywords, listBestSellerCategories, getProduct, listVariations,
4056
+ * listReviews, listRelatedProducts, listBestSellers, listNewReleases, listMostWishedFor,
4057
+ * listDeals, getSeller, getDeliveryEstimate and listSellerOffers are built; everything else is
4058
+ * still a declared stub.
4059
+ */
4060
+ interface Unit {
4061
+ /**
4062
+ * Search Amazon's catalogue for what a person would type — "cast iron skillet", "usb c hub" —
4063
+ * and get back the result cards as the site ranks them: ASIN, title, price, list price, star
4064
+ * rating, review count, whether the row is a paid placement, and its product URL. Optionally
4065
+ * narrowed to a department, a brand, a price range and a sort order. THE provider's door:
4066
+ * every function below that takes an ASIN is fed by this one.
4067
+ */
4068
+ searchProducts(args: SearchProductsArgs): Promise<AmazonProduct[]>;
4069
+
4070
+ /**
4071
+ * Ask Amazon's own search box what it would autocomplete a prefix to — "cast iron" comes back
4072
+ * as "cast iron skillets", "cast iron", "cast iron dutch oven". What an agent holding a vague
4073
+ * noun calls before it commits to a search, and the cheapest call in the provider.
4074
+ */
4075
+ suggestKeywords(prefix: string): Promise<AmazonKeywordSuggestion[]>;
4076
+
4077
+ /**
4078
+ * List the departments Amazon publishes Best Sellers rankings for — Electronics, Kitchen &
4079
+ * Dining, Books, roughly forty of them — each with the slug ("electronics", "kitchen",
4080
+ * "books") that listBestSellers, listNewReleases, listMostWishedFor and listMoversAndShakers
4081
+ * take. The door for all four ranking functions: a caller holding the word "kitchen" cannot
4082
+ * reach a ranking without this.
4083
+ */
4084
+ listBestSellerCategories(): Promise<AmazonBestSellerCategory[]>;
4085
+
4086
+ /**
4087
+ * Read one product page the way a shopper reads it: title, brand, ASIN, current price and list
4088
+ * price, whether it is in stock, the star rating and how many ratings it has, the bullet-point
4089
+ * features, the specification table, the images, its category breadcrumb, its Best Sellers
4090
+ * Rank, and who it is sold by. The single most-wanted read on the whole site.
4091
+ */
4092
+ getProduct(asinOrUrl: string): Promise<AmazonProductDetail>;
4093
+
4094
+ /**
4095
+ * List every version of a product that is really the same listing — the 8-inch, 10.25-inch,
4096
+ * 12-inch and 15-inch skillet; the colours; the pack sizes — each with the ASIN that buys it.
4097
+ * What an agent needs when the person said "the 12 inch one" and the search returned whichever
4098
+ * size Amazon ranked first. Empty when the listing has no variations — a real answer, not a
4099
+ * parse failure.
4100
+ */
4101
+ listVariations(asinOrUrl: string): Promise<AmazonVariation[]>;
4102
+
4103
+ /**
4104
+ * Read what customers actually wrote about a product — reviewer name, star rating, headline,
4105
+ * date, the variant they bought, whether the purchase was Verified, the review body, and how
4106
+ * many people found it helpful. Amazon shows a logged-out visitor its top eight reviews on the
4107
+ * product page itself; sorting, filtering and paging past them needs a signed-in account,
4108
+ * which sign-up has not shipped for yet. The read an agent needs to answer "is this any good"
4109
+ * rather than "what does it cost".
4110
+ */
4111
+ listReviews(asinOrUrl: string): Promise<AmazonReview[]>;
4112
+
4113
+ /**
4114
+ * The other products Amazon puts next to this one — "Frequently bought together" and
4115
+ * "Customers who viewed this item also viewed" — each with its ASIN, title, price and rating,
4116
+ * kept in separate arrays so a caller can tell a complement from a substitute. Names any
4117
+ * further rail Amazon lazy-loads rather than serving inline rather than silently dropping it.
4118
+ * How an agent moves from one product to the alternatives without inventing a new search
4119
+ * query.
4120
+ */
4121
+ listRelatedProducts(asinOrUrl: string): Promise<AmazonRelatedProducts>;
4122
+
4123
+ /**
4124
+ * Amazon's hourly-updated top sellers in one department (the slug listBestSellerCategories
4125
+ * returns, e.g. "kitchen") — each row's ASIN, rank, title, price and rating, in rank order.
4126
+ * What is actually selling right now, as opposed to searchProducts' relevance ranking. Page
4127
+ * one only (up to 30 rows) — Amazon publishes more per department across a paging control this
4128
+ * pass did not find.
4129
+ */
4130
+ listBestSellers(department: string): Promise<AmazonBestSellerEntry[]>;
4131
+
4132
+ /**
4133
+ * What is newly out in a department (the slug listBestSellerCategories returns, e.g.
4134
+ * "kitchen"), in Amazon's own hot-new-releases order — each row's ASIN, rank, title, price and
4135
+ * rating. The ranking a caller wants when "best seller" would only ever return the same
4136
+ * entrenched products. Page one only (up to 30 rows), the same limit listBestSellers carries
4137
+ * and for the same reason.
4138
+ */
4139
+ listNewReleases(department: string): Promise<AmazonBestSellerEntry[]>;
4140
+
4141
+ /**
4142
+ * What people in a department (the slug listBestSellerCategories returns, e.g. "kitchen") are
4143
+ * adding to wish lists and registries most — each row's ASIN, rank, title, price and rating.
4144
+ * Demand that has not turned into a purchase yet, which is a different signal from
4145
+ * listBestSellers' sales rank. Page one only (up to 30 rows), the same limit the other
4146
+ * rankings carry.
4147
+ */
4148
+ listMostWishedFor(department: string): Promise<AmazonBestSellerEntry[]>;
4149
+
4150
+ /**
4151
+ * Today's Deals — what is discounted right now: ASIN, title, the deal price, the price it was,
4152
+ * the percentage off, and any "limited time" wording (a plain label, or, for a countdown deal,
4153
+ * the fragment plus its ISO deadline). Read off the page's own widget JSON rather than scraped
4154
+ * from a card, so the discount is a published field rather than something to compute. Page one
4155
+ * only (30 deals) — the site's own paging control was not found this pass.
4156
+ */
4157
+ listDeals(): Promise<AmazonDeal[]>;
4158
+
4159
+ /**
4160
+ * Read a marketplace seller's storefront — their name, feedback across four windows (30 days,
4161
+ * 90 days, the last 12 months and lifetime), the one positive-percentage figure Amazon
4162
+ * publishes (last 12 months only), their registered business name and address, and their
4163
+ * free-text "About Seller" text. What tells an agent whether the cheap third-party offer is
4164
+ * from a shop with 86,000 ratings or one with thirty. The door is getProduct's sellerId field
4165
+ * — a listing Amazon sells itself has none.
4166
+ */
4167
+ getSeller(sellerId: string): Promise<AmazonSeller>;
4168
+
4169
+ /**
4170
+ * When a product would actually arrive at a given US ZIP, and what it costs to get it there —
4171
+ * sets the ZIP for one session (Amazon's own "glow" location picker, no account needed) and
4172
+ * reads the delivery block the product page then re-renders for it: the site's own delivery
4173
+ * sentence, the price label and the condition it attaches. `zipResolved` is false, and the
4174
+ * three fields are Amazon's DEFAULT location rather than the caller's ZIP, on an invalid ZIP.
4175
+ */
4176
+ getDeliveryEstimate(args: GetDeliveryEstimateArgs): Promise<AmazonDeliveryEstimate>;
4177
+
4178
+ /**
4179
+ * Every seller offering the same listing side by side — condition (new, used, its grade),
4180
+ * price, shipping cost and estimate, and the seller's own name, id and star rating — read off
4181
+ * the site's "All Offers Display" modal rather than the buy-box winner alone. What tells an
4182
+ * agent who has it cheapest, and whether the cheap one is Amazon itself or a thirty-rating
4183
+ * marketplace seller. Page one only (up to 10 offers, `totalOfferCount` reports the site's own
4184
+ * full count) — no paging control was found in the modal's static markup this pass. Empty
4185
+ * `offers` on a listing with no other sellers is a real answer, not a parse failure.
4186
+ */
4187
+ listSellerOffers(asinOrUrl: string): Promise<AmazonSellerOffersResult>;
4188
+ }
4189
+ }
4190
+
3720
4191
  declare namespace BowmarkProvider_americandreamvacations {
3721
4192
  // ── American Dream Vacations — the unit's own declarations, verbatim ──
3722
4193
  interface AdvLocation {
@@ -4179,6 +4650,300 @@ interface AosomProduct {
4179
4650
  }
4180
4651
  }
4181
4652
 
4653
+ declare namespace BowmarkProvider_app_store {
4654
+ // ── Apple App Store — the unit's own declarations, verbatim ──
4655
+ interface AppStoreApp {
4656
+ id: string;
4657
+ name: string;
4658
+ bundleId: string;
4659
+ developer: { id: string; name: string };
4660
+ price: { amount: number; currency: string; formatted: string } | null;
4661
+ rating: { average: number; count: number } | null;
4662
+ category: string;
4663
+ url: string;
4664
+ }
4665
+ type AppStorePlatform = "iphone" | "ipad" | "mac";
4666
+ interface SearchAppsArgs {
4667
+ term: string;
4668
+ platform?: AppStorePlatform;
4669
+ genreId?: string | number;
4670
+ country?: string;
4671
+ limit?: number;
4672
+ }
4673
+ interface AppStoreSearchResult {
4674
+ term: string;
4675
+ platform: AppStorePlatform;
4676
+ country: string;
4677
+ total: number;
4678
+ apps: AppStoreApp[];
4679
+ }
4680
+ interface GetAppArgs {
4681
+ app: string | number;
4682
+ country?: string;
4683
+ }
4684
+ interface GetAppsArgs {
4685
+ apps: (string | number)[];
4686
+ country?: string;
4687
+ }
4688
+ interface GetAppsResult {
4689
+ apps: AppStoreApp[];
4690
+ warnings: string[];
4691
+ }
4692
+ interface GetAppDetailsArgs {
4693
+ app: string | number;
4694
+ }
4695
+ interface AppStoreRatingHistogram {
4696
+ average: number;
4697
+ total: number;
4698
+ counts: number[];
4699
+ }
4700
+ interface AppStoreChartPosition {
4701
+ category: string;
4702
+ position: number;
4703
+ }
4704
+ interface AppStoreInAppPurchase {
4705
+ name: string;
4706
+ price: string;
4707
+ }
4708
+ interface AppStorePrivacyCategory {
4709
+ type: string;
4710
+ title: string;
4711
+ categories: string[];
4712
+ }
4713
+ interface AppStoreVersionInfo {
4714
+ version: string | null;
4715
+ releaseDate: string | null;
4716
+ notes: string;
4717
+ }
4718
+ interface AppStoreLink {
4719
+ label: string;
4720
+ url: string;
4721
+ }
4722
+ interface AppStoreFeaturedStory {
4723
+ title: string;
4724
+ url: string;
4725
+ }
4726
+ interface AppStoreAppDetails {
4727
+ id: string;
4728
+ url: string;
4729
+ ratings: AppStoreRatingHistogram | null;
4730
+ chartPosition: AppStoreChartPosition | null;
4731
+ editorsChoice: boolean;
4732
+ information: Record<string, string>;
4733
+ inAppPurchases: AppStoreInAppPurchase[];
4734
+ privacy: AppStorePrivacyCategory[];
4735
+ mostRecentVersion: AppStoreVersionInfo | null;
4736
+ accessibilityFeatures: string[];
4737
+ links: AppStoreLink[];
4738
+ featuredIn: AppStoreFeaturedStory[];
4739
+ }
4740
+ interface AppStoreCategory {
4741
+ id: string;
4742
+ name: string;
4743
+ parentId: string | null;
4744
+ }
4745
+ interface ListCategoriesResult {
4746
+ categories: AppStoreCategory[];
4747
+ }
4748
+ type AppStoreChartDevice = "iphone" | "ipad" | "mac";
4749
+ type AppStoreChartKind = "free" | "paid";
4750
+ interface ListTopChartsArgs {
4751
+ device?: AppStoreChartDevice;
4752
+ chart?: AppStoreChartKind;
4753
+ genreId?: string | number;
4754
+ limit?: number;
4755
+ }
4756
+ interface AppStoreChartApp {
4757
+ position: number;
4758
+ id: string;
4759
+ bundleId: string;
4760
+ name: string;
4761
+ subtitle: string;
4762
+ developer: string;
4763
+ ageRating: string;
4764
+ price: string;
4765
+ rating: { average: number; countLabel: string } | null;
4766
+ url: string;
4767
+ }
4768
+ interface ListTopChartsResult {
4769
+ device: AppStoreChartDevice;
4770
+ chart: AppStoreChartKind;
4771
+ genreId: string;
4772
+ source: "page" | "feed";
4773
+ apps: AppStoreChartApp[];
4774
+ }
4775
+ interface ListDeveloperAppsArgs {
4776
+ developer?: string | number;
4777
+ app?: string | number;
4778
+ country?: string;
4779
+ limit?: number;
4780
+ }
4781
+ interface ListDeveloperAppsResult {
4782
+ developer: { id: string; name: string };
4783
+ apps: AppStoreApp[];
4784
+ }
4785
+ interface ListSimilarAppsArgs {
4786
+ app: string | number;
4787
+ }
4788
+ interface AppStoreSimilarApp {
4789
+ id: string;
4790
+ bundleId: string;
4791
+ name: string;
4792
+ subtitle: string;
4793
+ ageRating: string;
4794
+ price: string;
4795
+ rating: { average: number; countLabel: string } | null;
4796
+ url: string;
4797
+ }
4798
+ interface AppStoreSimilarAppsResult {
4799
+ id: string;
4800
+ apps: AppStoreSimilarApp[];
4801
+ }
4802
+ interface GetStoryArgs {
4803
+ story: string | number;
4804
+ platform?: AppStoreChartDevice;
4805
+ }
4806
+ interface AppStoreStoryApp {
4807
+ id: string;
4808
+ bundleId: string;
4809
+ name: string;
4810
+ subtitle: string;
4811
+ developer: string;
4812
+ ageRating: string;
4813
+ rating: { average: number; countLabel: string } | null;
4814
+ price: string;
4815
+ url: string;
4816
+ }
4817
+ interface AppStoreStory {
4818
+ id: string;
4819
+ url: string;
4820
+ heading: string;
4821
+ title: string;
4822
+ subtitle: string;
4823
+ body: string;
4824
+ apps: AppStoreStoryApp[];
4825
+ }
4826
+ type AppStoreReviewSort = "mostRecent" | "mostHelpful";
4827
+ interface ListReviewsArgs {
4828
+ app: string | number;
4829
+ page?: number;
4830
+ sortBy?: AppStoreReviewSort;
4831
+ country?: string;
4832
+ }
4833
+ interface AppStoreReview {
4834
+ id: string;
4835
+ author: string;
4836
+ title: string;
4837
+ body: string;
4838
+ rating: number | null;
4839
+ version: string;
4840
+ helpfulVotes: number;
4841
+ totalVotes: number;
4842
+ updated: string;
4843
+ }
4844
+ interface ListReviewsResult {
4845
+ app: string;
4846
+ page: number;
4847
+ sortBy: AppStoreReviewSort;
4848
+ country: string;
4849
+ hasMore: boolean;
4850
+ reviews: AppStoreReview[];
4851
+ }
4852
+
4853
+ /**
4854
+ * Search every iPhone, iPad and Mac app Apple lists, read one app's price, rating, reviews,
4855
+ * in-app purchases and privacy labels, and see what is charting right now — off Apple's own
4856
+ * keyless public API and its server-rendered store pages.
4857
+ */
4858
+ interface Unit {
4859
+ /**
4860
+ * Search the App Store for what a person would actually type — "budget tracker", "slack",
4861
+ * "photo editor" — and get back the apps Apple's own store search ranks, narrowable by
4862
+ * platform (iPhone/iPad/Mac), category and store country. THE door: every id-taking function
4863
+ * in this provider is fed by an id this returns.
4864
+ */
4865
+ searchApps(args: SearchAppsArgs): Promise<AppStoreSearchResult>;
4866
+
4867
+ /**
4868
+ * Read one app the way its store listing reads: name, developer, price, average rating and
4869
+ * rating count, category, and the id every other function here takes — from a numeric app id,
4870
+ * its bundle id, or an apps.apple.com URL a person pasted. The core read of the provider, and
4871
+ * the cheapest call in it.
4872
+ */
4873
+ getApp(args: GetAppArgs): Promise<AppStoreApp>;
4874
+
4875
+ /**
4876
+ * Read up to fifty apps in ONE request, for when an agent already holds a list of ids — the
4877
+ * ranks past the top of a chart, the ids in a "you might also like" shelf, a comparison a
4878
+ * person asked for. Same record as getApp, one round trip instead of fifty; an id that does
4879
+ * not resolve is named in warnings rather than silently dropped.
4880
+ */
4881
+ getApps(args: GetAppsArgs): Promise<GetAppsResult>;
4882
+
4883
+ /**
4884
+ * Everything the store page shows that the API does not: the five-star rating histogram, the
4885
+ * app's live chart position, every in-app purchase by name and price, Apple's privacy
4886
+ * nutrition labels, the Editors' Choice citation, the latest version's notes, size, seller,
4887
+ * compatibility, languages, copyright, accessibility features, developer-website and
4888
+ * privacy-policy links, and the editorial stories it has been featured in. Every field is
4889
+ * optional — a missing shelf on the app's own page is an absent field here, never a throw.
4890
+ */
4891
+ getAppDetails(args: GetAppDetailsArgs): Promise<AppStoreAppDetails>;
4892
+
4893
+ /**
4894
+ * Answer "what else is like this one" with the App Store's own You Might Also Like shelf — the
4895
+ * apps Apple itself puts next to this one, each with its name, tagline, developer, age rating,
4896
+ * price and the id every function here takes. What an agent reaches for when the app a person
4897
+ * named is wrong, too expensive, or not on their device. Shares getAppDetails' page cache, so
4898
+ * calling both for one app costs one fetch.
4899
+ */
4900
+ listSimilarApps(args: ListSimilarAppsArgs): Promise<AppStoreSimilarAppsResult>;
4901
+
4902
+ /**
4903
+ * List every app one developer has on the store — from the developer's numeric artist id,
4904
+ * their apps.apple.com developer URL, or just one of their apps (resolved to its developer
4905
+ * first). The read behind "what else did the people who made this write" and behind checking
4906
+ * whether an app is from who it claims to be.
4907
+ */
4908
+ listDeveloperApps(args: ListDeveloperAppsArgs): Promise<ListDeveloperAppsResult>;
4909
+
4910
+ /**
4911
+ * List every category and subcategory the App Store sorts apps into — Business, Education,
4912
+ * Games and its nineteen sub-genres, and the rest — each with the numeric id that narrows
4913
+ * searchApps and listTopCharts. The finder that lets an agent holding the word "puzzle" reach
4914
+ * a real listing without being told an id.
4915
+ */
4916
+ listCategories(): Promise<ListCategoriesResult>;
4917
+
4918
+ /**
4919
+ * What is charting on the App Store right now — top free or top paid, on iPhone, iPad or Mac,
4920
+ * for the whole store or narrowed to any genre id listCategories returns — in rank order, each
4921
+ * entry with its position, name, tagline, developer, age rating, price and the id every other
4922
+ * function here takes. The question this provider exists to answer that no search engine
4923
+ * answers, because the answer changes every day.
4924
+ */
4925
+ listTopCharts(args?: ListTopChartsArgs): Promise<ListTopChartsResult>;
4926
+
4927
+ /**
4928
+ * Read an App Store editorial story — the Today-tab piece Apple's editors wrote ("Master Your
4929
+ * Major", "About In-App Purchases") — its heading, title, body and the apps it recommends,
4930
+ * each with the id every other function here takes. Takes the story URL
4931
+ * getAppDetails().featuredIn[].url returns, or a bare story id plus the platform it was
4932
+ * featured under. How an agent answers "what does Apple say about this" and finds apps nobody
4933
+ * searches for by name.
4934
+ */
4935
+ getStory(args: GetStoryArgs): Promise<AppStoreStory>;
4936
+
4937
+ /**
4938
+ * Read what people actually wrote about an app — the review body, its title, the star rating,
4939
+ * the reviewer's name, which app version they were on, and how many others found it helpful —
4940
+ * fifty at a time, newest first or most helpful first. The one read that turns "4.1 stars"
4941
+ * into a reason.
4942
+ */
4943
+ listReviews(args: ListReviewsArgs): Promise<ListReviewsResult>;
4944
+ }
4945
+ }
4946
+
4182
4947
  declare namespace BowmarkProvider_apple {
4183
4948
  // ── Apple — the unit's own declarations, verbatim ──
4184
4949
  interface AppleSearchResult {
@@ -4192,6 +4957,15 @@ interface AppleSearchResponse {
4192
4957
  query: string;
4193
4958
  results: AppleSearchResult[];
4194
4959
  }
4960
+ interface AppleSuggestionRow {
4961
+ label: string;
4962
+ url: string;
4963
+ }
4964
+ interface AppleSuggestResponse {
4965
+ query: string;
4966
+ suggestions: AppleSuggestionRow[];
4967
+ quickLinks: AppleSuggestionRow[];
4968
+ }
4195
4969
  interface AppleProduct {
4196
4970
  name: string;
4197
4971
  lowPrice: number | null;
@@ -4204,11 +4978,158 @@ interface AppleProductPage {
4204
4978
  url: string;
4205
4979
  products: AppleProduct[];
4206
4980
  }
4981
+ interface AppleConfigChoice {
4982
+ key: string;
4983
+ label: string;
4984
+ }
4985
+ interface AppleConfigDimension {
4986
+ key: string;
4987
+ label: string;
4988
+ choices: AppleConfigChoice[];
4989
+ }
4990
+ interface AppleConfiguration {
4991
+ dimensions: Record<string, string>;
4992
+ partNumber: string | null;
4993
+ buildToOrder: boolean;
4994
+ price: number | null;
4995
+ priceCurrency: string | null;
4996
+ }
4997
+ interface AppleConfigurationOptions {
4998
+ url: string;
4999
+ dimensions: AppleConfigDimension[];
5000
+ configDimensions: AppleConfigDimension[];
5001
+ configurations: AppleConfiguration[];
5002
+ }
5003
+ interface AppleFamilyModel {
5004
+ name: string;
5005
+ startingPrice: number | null;
5006
+ url: string;
5007
+ }
5008
+ interface AppleFamilyModelList {
5009
+ family: "mac" | "iphone" | "ipad" | "watch";
5010
+ models: AppleFamilyModel[];
5011
+ }
5012
+ interface AppleRefurbishedListing {
5013
+ partNumber: string;
5014
+ name: string;
5015
+ price: number | null;
5016
+ priceCurrency: string | null;
5017
+ url: string;
5018
+ image: string | null;
5019
+ }
5020
+ interface AppleRefurbishedCatalog {
5021
+ category: "mac" | "ipad" | "iphone" | "watch" | "appletv" | "homepod" | "airpods" | "accessories";
5022
+ listings: AppleRefurbishedListing[];
5023
+ }
4207
5024
  interface AppleTradeInEstimate {
4208
5025
  device: string;
4209
5026
  upToUsd: number;
4210
5027
  sourceUrl: string;
4211
5028
  }
5029
+ interface AppleTradeInDeviceValue {
5030
+ modelId: string | null;
5031
+ modelName: string;
5032
+ maxValueUsd: number;
5033
+ }
5034
+ interface AppleTradeInCatalog {
5035
+ category: "smartphone" | "computer" | "watch";
5036
+ devices: AppleTradeInDeviceValue[];
5037
+ }
5038
+ interface AppleSupportResult {
5039
+ docid: string;
5040
+ title: string;
5041
+ url: string;
5042
+ snippet: string;
5043
+ }
5044
+ interface AppleSupportSearchResponse {
5045
+ query: string;
5046
+ results: AppleSupportResult[];
5047
+ totalResults: number;
5048
+ }
5049
+ interface AppleSupportArticle {
5050
+ docid: string;
5051
+ title: string;
5052
+ description: string;
5053
+ url: string;
5054
+ body: string;
5055
+ }
5056
+ interface AppleLocationSuggestion {
5057
+ displayValue: string;
5058
+ city: string;
5059
+ state: string;
5060
+ }
5061
+ interface AppleResolvedLocation {
5062
+ place: string;
5063
+ location: string;
5064
+ city: string;
5065
+ state: string;
5066
+ alternates: AppleLocationSuggestion[];
5067
+ }
5068
+ interface AppleNearbyStore {
5069
+ storeNumber: string;
5070
+ storeName: string;
5071
+ city: string;
5072
+ state: string;
5073
+ address: string;
5074
+ phoneNumber: string;
5075
+ distanceMiles: number | null;
5076
+ }
5077
+ interface AppleStoresNear {
5078
+ location: string;
5079
+ stores: AppleNearbyStore[];
5080
+ }
5081
+ interface ApplePickupStore {
5082
+ storeNumber: string;
5083
+ storeName: string;
5084
+ city: string;
5085
+ state: string;
5086
+ address: string;
5087
+ phoneNumber: string;
5088
+ distanceMiles: number | null;
5089
+ available: boolean;
5090
+ pickupQuote: string | null;
5091
+ }
5092
+ interface ApplePickupAvailability {
5093
+ partNumber: string;
5094
+ location: string;
5095
+ stores: ApplePickupStore[];
5096
+ }
5097
+ interface AppleDeliveryOption {
5098
+ displayName: string;
5099
+ date: string;
5100
+ shippingCost: string;
5101
+ }
5102
+ interface AppleDeliveryEstimate {
5103
+ partNumber: string;
5104
+ postalCode: string;
5105
+ options: AppleDeliveryOption[];
5106
+ }
5107
+ interface AppleStoreListing {
5108
+ storeNumber: string;
5109
+ name: string;
5110
+ url: string;
5111
+ }
5112
+ interface AppleStoreList {
5113
+ stores: AppleStoreListing[];
5114
+ }
5115
+ interface AppleStoreHours {
5116
+ days: string[];
5117
+ opens: string;
5118
+ closes: string;
5119
+ }
5120
+ interface AppleStore {
5121
+ storeNumber: string;
5122
+ name: string;
5123
+ url: string;
5124
+ phoneNumber: string;
5125
+ address: string;
5126
+ city: string;
5127
+ state: string;
5128
+ postalCode: string;
5129
+ latitude: number | null;
5130
+ longitude: number | null;
5131
+ hours: AppleStoreHours[];
5132
+ }
4212
5133
 
4213
5134
  /** apple.com's own site search and product pages — no API, no login, no browser. */
4214
5135
  interface Unit {
@@ -4218,12 +5139,59 @@ interface AppleTradeInEstimate {
4218
5139
  */
4219
5140
  search(query: string): Promise<AppleSearchResponse>;
4220
5141
 
5142
+ /**
5143
+ * Types a partial query into apple.com's own search box and returns what it suggests:
5144
+ * completed search phrases ("AirPods Pro 3") and quick links straight to a product page
5145
+ * ("AirPods" → apple.com/airpods/). A caller holding only the words somebody said gets a real
5146
+ * product URL with no id to know first.
5147
+ */
5148
+ suggestSearches(query: string): Promise<AppleSuggestResponse>;
5149
+
4221
5150
  /**
4222
5151
  * Reads one apple.com product/buy page (a URL or path, e.g. search()'s own rows) and returns
4223
5152
  * every schema.org Product block it publishes.
4224
5153
  */
4225
5154
  getProduct(urlOrPath: string): Promise<AppleProductPage>;
4226
5155
 
5156
+ /**
5157
+ * Turns an Apple part number — the "MYAP3LL/A"-shaped code printed on every buy page and
5158
+ * returned by getPickupAvailability/getDeliveryEstimate — into the product it names: real
5159
+ * name, price and currency, straight off the configured buy page apple.com redirects a part
5160
+ * number to. Also accepts a /shop/ path or apple.com URL, resolved the same way getProduct's
5161
+ * argument is.
5162
+ */
5163
+ getProductByPartNumber(partNumber: string): Promise<AppleProductPage>;
5164
+
5165
+ /**
5166
+ * Reads every choice a Mac/iPhone/iPad buy page actually offers — screen size, colour, chip,
5167
+ * memory, storage, keyboard layout, connectivity — straight off the page's own configurator
5168
+ * data, with the part number and price each fixed combination already resolves to. "Configure
5169
+ * and price it" as one read instead of clicking through the on-page configurator: every part
5170
+ * number this returns is directly usable by getProductByPartNumber, getPickupAvailability and
5171
+ * getDeliveryEstimate. A combination apple.com has not fixed a single part number for yet
5172
+ * (memory/storage still open) comes back with `buildToOrder: true` and a null part number,
5173
+ * listing the further choices rather than guessing a price for combinations apple.com computes
5174
+ * client-side.
5175
+ */
5176
+ getConfigurationOptions(urlOrPath: string): Promise<AppleConfigurationOptions>;
5177
+
5178
+ /**
5179
+ * Lists every model apple.com currently sells in one product family — the chooser page's own
5180
+ * cards (e.g. "MacBook Air", "iPad mini"), each with its starting price and the buy page that
5181
+ * configures it. Takes "mac", "iphone", "ipad" or "watch" — apple.com publishes no equivalent
5182
+ * chooser page for AirPods or Vision Pro, each sold as a single named model with no lineup to
5183
+ * list.
5184
+ */
5185
+ listFamilyModels(family: "mac" | "iphone" | "ipad" | "watch"): Promise<AppleFamilyModelList>;
5186
+
5187
+ /**
5188
+ * Apple's own certified refurbished store, read as data: every listing currently in stock in
5189
+ * one category, each with its real name, its current price and the part number that resolves
5190
+ * it straight through getProductByPartNumber. Stock turns over daily and a category can
5191
+ * legitimately be empty when Apple has nothing left in it.
5192
+ */
5193
+ listRefurbished(category: "mac" | "ipad" | "iphone" | "watch" | "appletv" | "homepod" | "airpods" | "accessories"): Promise<AppleRefurbishedCatalog>;
5194
+
4227
5195
  /**
4228
5196
  * Reads apple.com's own trade-in value table and returns the CEILING ("up to $X")
4229
5197
  * cash-or-credit estimate it publishes for one device — a human name ("iPhone 14 Pro") or the
@@ -4232,6 +5200,82 @@ interface AppleTradeInEstimate {
4232
5200
  * best-case figure, not a quote for a specific unit's actual condition.
4233
5201
  */
4234
5202
  getTradeInEstimate(model: string): Promise<AppleTradeInEstimate>;
5203
+
5204
+ /**
5205
+ * The whole Apple Trade In price list in one call. "smartphone" is the RICH catalog behind the
5206
+ * estimator — every individual phone model apple.com will take, INCLUDING non-Apple ones
5207
+ * (Samsung, Google, …), each with its own ceiling. "computer" and "watch" are coarser: a
5208
+ * ceiling per product LINE ("MacBook Pro", "Apple Watch Ultra 3"), the same table
5209
+ * getTradeInEstimate reads for iPhone. apple.com has no measured trade-in catalog for "tablet"
5210
+ * at all — neither surface this function uses covers it.
5211
+ */
5212
+ listTradeInValues(category: "smartphone" | "computer" | "watch"): Promise<AppleTradeInCatalog>;
5213
+
5214
+ /**
5215
+ * Searches Apple's own support library the way a person describes a problem ("iphone battery
5216
+ * draining") and returns the articles Apple ranks for it — HelpKB pages, User Guide pages and
5217
+ * Apple Support Community threads mixed in one list, each with its document id, title, URL and
5218
+ * a plain-text snippet. A DOOR: the way into the support half of this provider before
5219
+ * getSupportArticle reads one page in full.
5220
+ */
5221
+ searchSupport(query: string): Promise<AppleSupportSearchResponse>;
5222
+
5223
+ /**
5224
+ * Reads one Apple support article end to end — the real instructions under its headline, not a
5225
+ * search snippet — from the docid or URL one of searchSupport()'s own rows carries. The read
5226
+ * an agent reaches for once searchSupport has narrowed the problem to one page.
5227
+ */
5228
+ getSupportArticle(docidOrUrl: string): Promise<AppleSupportArticle>;
5229
+
5230
+ /**
5231
+ * Turns the place a person said — "cupertino", "san francisco" — into the exact "<city>,
5232
+ * <state>" string apple.com's own store and delivery lookups accept, off apple.com's own
5233
+ * location typeahead. A DOOR HOP: the small step that makes findStoresNear,
5234
+ * getPickupAvailability and getDeliveryEstimate callable from words alone instead of a
5235
+ * pre-resolved location string.
5236
+ */
5237
+ resolveLocation(place: string): Promise<AppleResolvedLocation>;
5238
+
5239
+ /**
5240
+ * Finds the Apple Stores near a place a person named — "Cupertino", "94108", "San Francisco" —
5241
+ * with each store's name, number, city, state, address, phone and distance, nearest first. The
5242
+ * finder that turns a place into the store records every other retail function here takes, for
5243
+ * a caller who holds no part number and must not have to invent one.
5244
+ */
5245
+ findStoresNear(place: string): Promise<AppleStoresNear>;
5246
+
5247
+ /**
5248
+ * Answers the one question apple.com is uniquely able to answer: can I walk into a store today
5249
+ * and pick this up. Give it a part number (or a /shop/ path or apple.com URL — resolved the
5250
+ * same way getProduct's argument is) and a place, and it returns every nearby Apple Store with
5251
+ * whether that exact configuration is in stock, the pickup window, and the store's name,
5252
+ * number, address, phone and distance.
5253
+ */
5254
+ getPickupAvailability(partNumber: string, place: string): Promise<ApplePickupAvailability>;
5255
+
5256
+ /**
5257
+ * When would this actually arrive if ordered now, to a ZIP code — the shipping options and
5258
+ * delivery dates apple.com quotes on the buy page for one exact configuration, without
5259
+ * starting a checkout. Takes a bare 5-digit ZIP, NOT the resolved place string
5260
+ * getPickupAvailability takes: apple.com's own delivery-message endpoint reads a different
5261
+ * parameter and ignores a "<city>, <state>" value entirely.
5262
+ */
5263
+ getDeliveryEstimate(partNumber: string, postalCode: string): Promise<AppleDeliveryEstimate>;
5264
+
5265
+ /**
5266
+ * Every Apple Store in the US on one call — its name, its store number and its page — off
5267
+ * apple.com's own store-locator directory, so a caller can browse or filter them rather than
5268
+ * guess a slug. The store number is the SAME id findStoresNear and getPickupAvailability's
5269
+ * rows carry, so a listing here joins straight to either.
5270
+ */
5271
+ listStores(): Promise<AppleStoreList>;
5272
+
5273
+ /**
5274
+ * Read one Apple Store: its full address, phone number, map coordinates, store number and the
5275
+ * hours it is open each day of the week — everything a person needs before driving there.
5276
+ * Takes a URL or /retail/ path, e.g. one of listStores()'s own rows.
5277
+ */
5278
+ getStore(urlOrPath: string): Promise<AppleStore>;
4235
5279
  }
4236
5280
  }
4237
5281
 
@@ -4402,11 +5446,59 @@ interface archive_orgAvailability {
4402
5446
  archivedStatus: string | null; // the original page's own HTTP status when captured
4403
5447
  }
4404
5448
 
5449
+ interface archive_orgSnapshotOptions {
5450
+ scope?: "exact" | "prefix"; // default: "prefix" for a bare domain (every page under it), "exact" for a url with a path
5451
+ limit?: number; // 1-500, default 50 — newest first
5452
+ pathContains?: string[]; // keep only urls whose path contains one of these, e.g. ["about", "team", "contact"]
5453
+ }
5454
+
5455
+ interface archive_orgSnapshot {
5456
+ timestamp: string; // YYYYMMDDhhmmss
5457
+ originalUrl: string;
5458
+ archivedUrl: string; // the browsable capture, web.archive.org/web/<ts>/<url>
5459
+ statusCode: string;
5460
+ mimeType: string;
5461
+ }
5462
+
5463
+ interface archive_orgSnapshotList {
5464
+ query: string;
5465
+ scope: "exact" | "prefix";
5466
+ snapshots: archive_orgSnapshot[]; // prefix: newest capture of each distinct url; exact: each distinct VERSION of the page
5467
+ warnings: string[];
5468
+ }
5469
+
5470
+ interface archive_orgSnapshotPage {
5471
+ originalUrl: string;
5472
+ timestamp: string;
5473
+ archivedUrl: string;
5474
+ html: string; // the ORIGINAL bytes as captured, without the archive's toolbar or rewritten links
5475
+ warnings: string[];
5476
+ }
5477
+
4405
5478
  /**
4406
- * The Wayback Machine's own public availability lookup — is a site or page archived, and
4407
- * where.
5479
+ * The Wayback Machine — is a site or page archived, every capture it holds, and the page
5480
+ * itself as it was captured, so a caller can see what a site published before it was changed
5481
+ * or removed.
4408
5482
  */
4409
5483
  interface Unit {
5484
+ /**
5485
+ * Lists what the Wayback Machine has captured, newest first. A bare domain ("humanlayer.dev")
5486
+ * returns the newest capture of every distinct page under it — narrow it with `pathContains:
5487
+ * ["about", "team", "contact"]`. A url with a path returns every distinct VERSION of that one
5488
+ * page, which is the axis that answers "was this ever on the page". Each row carries the
5489
+ * capture timestamp, the original url and its browsable archive url. Use getSnapshot to read
5490
+ * one.
5491
+ */
5492
+ listSnapshots(site: string, opts?: archive_orgSnapshotOptions): Promise<archive_orgSnapshotList>;
5493
+
5494
+ /**
5495
+ * Reads one archived page as it was captured — the original HTML, without the archive's
5496
+ * toolbar or rewritten links — for a url and a `YYYYMMDDhhmmss` timestamp from listSnapshots
5497
+ * (a nearby timestamp is redirected to the closest capture). Use it to find something a page
5498
+ * carried in the past and has since removed.
5499
+ */
5500
+ getSnapshot(url: string, timestamp: string): Promise<archive_orgSnapshotPage>;
5501
+
4410
5502
  /**
4411
5503
  * Checks the Wayback Machine's own public availability endpoint for one site or page — a bare
4412
5504
  * domain ("carpetlandusa.net"), a domain plus path
@@ -5896,15 +6988,17 @@ interface bestbuyProduct {
5896
6988
  * Runs a Best Buy product search the way bestbuy.com's own search box does, via Best Buy's
5897
6989
  * documented Products API, and returns the matching products — name, sale/regular price,
5898
6990
  * online and in-store availability, manufacturer, model number, UPC and review stats.
5899
- * `pageSize` caps the row count (default 10, Best Buy's own ceiling 100). Requires a Best Buy
5900
- * developer API key see this provider's `auth`.
6991
+ * `pageSize` caps the row count (default 10, Best Buy's own ceiling 100). Uses Bowmark's Best
6992
+ * Buy key and charges each request to your account; send your own key as the
6993
+ * `x-bowmark-vendor-key-bestbuy` header instead.
5901
6994
  */
5902
6995
  search(args: string | { query: string; pageSize?: number }): Promise<bestbuyProduct[]>;
5903
6996
 
5904
6997
  /**
5905
6998
  * Looks up one product by Best Buy's own numeric SKU (the id `search`'s rows carry) and
5906
- * returns its full detail — the same fields as `search`. Requires a Best Buy developer API key
5907
- * see this provider's `auth`.
6999
+ * returns its full detail — the same fields as `search`. Uses Bowmark's Best Buy key and
7000
+ * charges each request to your account; send your own key as the
7001
+ * `x-bowmark-vendor-key-bestbuy` header instead.
5908
7002
  */
5909
7003
  getProduct(sku: string | number): Promise<bestbuyProduct>;
5910
7004
  }
@@ -7562,9 +8656,58 @@ interface CalComAvailabilityResult {
7562
8656
  otherEventTypes: CalComEventType[];
7563
8657
  }
7564
8658
 
8659
+ interface CalComFormQuestion {
8660
+ label: string; // what a booker reads
8661
+ name: string; // Cal.com's own field name ("name", "email", or a custom slug)
8662
+ type: string; // Cal.com's own type: "name" | "email" | "phone" | "text" | "textarea" | "select" | "radio" | …
8663
+ required: boolean;
8664
+ choices: string[];
8665
+ }
8666
+
8667
+ interface CalComBookingEvent {
8668
+ title: string;
8669
+ slug: string;
8670
+ url: string;
8671
+ description: string | null;
8672
+ lengthInMinutes: number | null;
8673
+ }
8674
+
8675
+ interface CalComBookingFormOptions {
8676
+ event?: string; // which event on a multi-event profile — its slug or part of its title
8677
+ }
8678
+
8679
+ interface CalComBookingForm {
8680
+ url: string;
8681
+ username: string;
8682
+ eventTypes: CalComEventType[]; // a profile's list; empty when the url already named an event
8683
+ event: CalComBookingEvent | null; // null when several events exist and none was named
8684
+ ownerName: string | null;
8685
+ organization: string | null; // the org/team Cal.com itself files the account under
8686
+ avatarUrl: string | null;
8687
+ questions: CalComFormQuestion[]; // only what a booker is shown — hidden and reschedule-only fields dropped
8688
+ warnings: string[];
8689
+ }
8690
+
8691
+ interface CalComProfileCandidate {
8692
+ slug: string;
8693
+ url: string; // where the page landed; a one-event profile redirects to that event
8694
+ title: string; // the page's own <title>
8695
+ ownerName: string | null; // read off the title
8696
+ nameMatches: boolean; // ownerName carries BOTH names asked for — a hint, a namesake passes too
8697
+ }
8698
+
8699
+ interface CalComFindProfilesResult {
8700
+ name: string;
8701
+ company: string | null;
8702
+ slugsChecked: string[];
8703
+ candidates: CalComProfileCandidate[];
8704
+ warnings: string[];
8705
+ }
8706
+
7565
8707
  /**
7566
- * Cal.com's own documented, keyless public APIthe event types a booking page offers and the
7567
- * real, currently-open time slots for one of them no browser, no key.
8708
+ * Cal.com's own public surfacesfind a person's Cal.com page from their name, read the event
8709
+ * types it offers, the questions its booking form asks and who owns it, and the real,
8710
+ * currently-open time slots — no browser, no key.
7568
8711
  */
7569
8712
  interface Unit {
7570
8713
  /**
@@ -7581,6 +8724,28 @@ interface CalComAvailabilityResult {
7581
8724
  * event type and reports the rest in `otherEventTypes`.
7582
8725
  */
7583
8726
  getAvailability(username: string, opts?: CalComAvailabilityOptions): Promise<CalComAvailabilityResult>;
8727
+
8728
+ /**
8729
+ * Reads what a Cal.com booking page will ask before anyone books: the event's
8730
+ * title/description/length, every question on its booking form (only the ones a booker is
8731
+ * actually shown, with choices and whether each is required), the owner's name and avatar, and
8732
+ * the organization or team Cal.com files the account under. Needs no open slot. Takes an event
8733
+ * url ("https://cal.com/alexatallah/15min"), a team or org-subdomain event url, or a profile
8734
+ * url — a profile with several events returns `event: null` and the list unless `opts.event`
8735
+ * names one. Never books anything.
8736
+ */
8737
+ getBookingForm(url: string, opts?: CalComBookingFormOptions): Promise<CalComBookingForm>;
8738
+
8739
+ /**
8740
+ * Finds a person's own Cal.com page from their full name, and optionally their company (pass
8741
+ * it). Checks the slug shapes that measured reliable (first-last, firstlast, lastfirst,
8742
+ * first-company, firstcompany, last-company, and the bare company slug — which often belongs
8743
+ * to a stranger, so read `ownerName`) and returns each page that exists with its own title,
8744
+ * the owner name the title states, and `nameMatches`. A match is a GUESS: a namesake passes,
8745
+ * so tie the page to the company before relying on it. Works on pages no search engine has
8746
+ * indexed.
8747
+ */
8748
+ findProfiles(name: string, company?: string): Promise<CalComFindProfilesResult>;
7584
8749
  }
7585
8750
  }
7586
8751
 
@@ -7629,10 +8794,58 @@ interface CalendlyAvailabilityResult {
7629
8794
  otherEventTypes: CalendlyEventType[];
7630
8795
  }
7631
8796
 
8797
+ interface CalendlyFormQuestion {
8798
+ label: string;
8799
+ format: string; // Calendly's own: "string" | "text" | "phone_number" | "select" | "multi_select" | "radios" | "checkboxes"
8800
+ required: boolean;
8801
+ choices: string[];
8802
+ }
8803
+
8804
+ interface CalendlyBookingEvent {
8805
+ name: string;
8806
+ slug: string | null;
8807
+ url: string;
8808
+ description: string | null;
8809
+ durationMinutes: number | null;
8810
+ }
8811
+
8812
+ interface CalendlyBookingFormOptions {
8813
+ event?: string; // which event on a multi-event profile — its slug or part of its name
8814
+ }
8815
+
8816
+ interface CalendlyBookingForm {
8817
+ url: string;
8818
+ profileSlug: string | null; // null for a calendly.com/d/<hash> share link
8819
+ ownerName: string | null;
8820
+ eventTypes: CalendlyEventType[];
8821
+ event: CalendlyBookingEvent | null; // null when several events exist and none was named
8822
+ questions: CalendlyFormQuestion[]; // CUSTOM questions; name + email are always asked on top
8823
+ nextAvailability: string | null; // null + unavailableReason null = fully booked, not unread
8824
+ unavailableReason: string | null; // non-null = Calendly says this cannot be booked
8825
+ warnings: string[];
8826
+ }
8827
+
8828
+ interface CalendlyProfileCandidate {
8829
+ slug: string;
8830
+ url: string;
8831
+ ownerName: string; // the name the profile itself shows
8832
+ nameMatches: boolean; // ownerName carries BOTH names asked for — a hint, a namesake passes too
8833
+ timezone: string;
8834
+ }
8835
+
8836
+ interface CalendlyFindProfilesResult {
8837
+ name: string;
8838
+ company: string | null;
8839
+ slugsChecked: string[];
8840
+ candidates: CalendlyProfileCandidate[];
8841
+ warnings: string[];
8842
+ }
8843
+
7632
8844
  /**
7633
- * Calendly's own public booking-widget data — the event types a scheduling page offers and the
7634
- * real, currently-open time slots for one of them read straight off the widget's
7635
- * undocumented JSON endpoints, no browser, no key.
8845
+ * Calendly's own public booking-widget data — find a person's Calendly page from their name,
8846
+ * read the event types it offers, the questions its booking form asks, and the real,
8847
+ * currently-open time slots — read straight off the widget's undocumented JSON endpoints, no
8848
+ * browser, no key.
7636
8849
  */
7637
8850
  interface Unit {
7638
8851
  /**
@@ -7650,6 +8863,29 @@ interface CalendlyAvailabilityResult {
7650
8863
  * first event type and reports the rest in `otherEventTypes`.
7651
8864
  */
7652
8865
  getAvailability(profile: string, opts?: CalendlyAvailabilityOptions): Promise<CalendlyAvailabilityResult>;
8866
+
8867
+ /**
8868
+ * Reads what a Calendly booking page will ask before anyone books: the owner's name, the
8869
+ * event's name/description/duration, every custom form question (with its choices and whether
8870
+ * it is required), the next open time, and Calendly's own reason when the calendar cannot be
8871
+ * booked. Needs no open slot, so it reads a fully-booked calendar too. Takes a profile url
8872
+ * ("https://calendly.com/eric-ciarla"), an event url, or a one-off share link
8873
+ * ("https://calendly.com/d/ctbt-d45-rgb/simbie-ai-demo"). A profile with several events
8874
+ * returns `event: null` and the list unless `opts.event` names one. Never books anything.
8875
+ */
8876
+ getBookingForm(url: string, opts?: CalendlyBookingFormOptions): Promise<CalendlyBookingForm>;
8877
+
8878
+ /**
8879
+ * Finds a person's own Calendly page from their full name, and optionally their company (pass
8880
+ * it — "caleb-firecrawl" is found only by the company shape). Checks the slug shapes that
8881
+ * measured reliable (first-last, firstlast, lastfirst, first-company, firstcompany,
8882
+ * last-company, and the bare company slug — which often belongs to a stranger, so read
8883
+ * `ownerName`) and returns every one that exists with the name the page itself shows and
8884
+ * `nameMatches`. A match is a GUESS: a namesake with the same first and last name passes, so
8885
+ * tie the page to the company before relying on it. Search engines do not index Calendly
8886
+ * pages, so this is the way to find one.
8887
+ */
8888
+ findProfiles(name: string, company?: string): Promise<CalendlyFindProfilesResult>;
7653
8889
  }
7654
8890
  }
7655
8891
 
@@ -10485,6 +11721,19 @@ interface CuriocityListEventsQuery {
10485
11721
  }
10486
11722
  }
10487
11723
 
11724
+ declare namespace BowmarkProvider_currency_exchange {
11725
+ // ── ExchangeRate-API — the unit's own declarations, verbatim ──
11726
+ interface currency_exchangeRow {
11727
+ rate: number;
11728
+ }
11729
+
11730
+ /** Get real-time exchange rates from ExchangeRate-API */
11731
+ interface Unit {
11732
+ /** Returns the current exchange rate between two currencies */
11733
+ getRate(from: string, to: string): Promise<currency_exchangeRow>;
11734
+ }
11735
+ }
11736
+
10488
11737
  declare namespace BowmarkProvider_cyberpowerpc {
10489
11738
  // ── CyberPowerPC — the unit's own declarations, verbatim ──
10490
11739
  interface CyberpowerpcConfigurator {
@@ -11025,6 +12274,29 @@ interface DdCartHandoff {
11025
12274
  }
11026
12275
  }
11027
12276
 
12277
+ declare namespace BowmarkProvider_dell {
12278
+ // ── Dell — the unit's own declarations, verbatim ──
12279
+ interface SearchForumThreadsArgs {
12280
+ query: string;
12281
+ }
12282
+
12283
+ interface DellForumThread {
12284
+ title: string;
12285
+ url: string;
12286
+ postCount: number;
12287
+ }
12288
+
12289
+ /** Search Dell's community forum for discussion threads. */
12290
+ interface Unit {
12291
+ /**
12292
+ * Search Dell community forums for threads matching a query — needs a topic or keywords (e.g.
12293
+ * "storage issues", "laptop battery"), never a bare "search the forum" with nothing to search
12294
+ * for.
12295
+ */
12296
+ searchForumThreads(args: SearchForumThreadsArgs): Promise<DellForumThread[]>;
12297
+ }
12298
+ }
12299
+
11028
12300
  declare namespace BowmarkProvider_deltadentalma {
11029
12301
  // ── Delta Dental of Massachusetts — the unit's own declarations, verbatim ──
11030
12302
  // Delta Dental of Massachusetts's OWN shapes — not a capability contract.
@@ -12354,7 +13626,8 @@ interface etsyListing {
12354
13626
  * Searches Etsy's live catalog of active listings by keyword, via Etsy's documented Open API
12355
13627
  * v3, and returns the matching listings — id, title, price, currency, quantity available, tags
12356
13628
  * and the listing's own etsy.com URL. `limit` caps the row count (default 10, Etsy's own
12357
- * ceiling 100). Requires an Etsy developer API key see this provider's `auth`.
13629
+ * ceiling 100). Uses Bowmark's Etsy key and charges each request to your account; send your
13630
+ * own key as the `x-bowmark-vendor-key-etsy` header instead.
12358
13631
  */
12359
13632
  search(args: string | { query: string; limit?: number }): Promise<etsyListing[]>;
12360
13633
  }
@@ -14608,6 +15881,19 @@ interface GithubListReleasesResult {
14608
15881
  warnings: string[];
14609
15882
  }
14610
15883
 
15884
+ interface GithubProfileReadme {
15885
+ login: string;
15886
+ name: string | null;
15887
+ company: string | null;
15888
+ blog: string | null; // the website they list on their profile
15889
+ bio: string | null;
15890
+ twitterUsername: string | null;
15891
+ profileUrl: string;
15892
+ readme: string | null; // the profile README's raw markdown; null when they have none
15893
+ readmeUrl: string | null;
15894
+ warnings: string[];
15895
+ }
15896
+
14611
15897
  /**
14612
15898
  * GitHub's own REST API, keyless. Built: a public repo's commit log (sha, author, date,
14613
15899
  * message), paged and windowed; a public repo's release history (tag, name, dates, release
@@ -14639,6 +15925,16 @@ interface GithubListReleasesResult {
14639
15925
  * `releases: []`, not a throw.
14640
15926
  */
14641
15927
  listReleases(owner: string, repo: string, options?: GithubListReleasesOptions): Promise<GithubListReleasesResult>;
15928
+
15929
+ /**
15930
+ * Reads a person's own GitHub profile — display name, company, the website they list, bio, X
15931
+ * handle — and the raw markdown of their profile README (the `<handle>/<handle>` repo GitHub
15932
+ * shows on the profile page), which is where people put a personal site, a booking link or
15933
+ * contact details. Takes a username, `@handle` or github.com url. `readme` is null when they
15934
+ * have no profile README. Unauthenticated calls share GitHub's 60 requests/hour per IP; this
15935
+ * spends two. THROWS on an unknown user or a rate limit.
15936
+ */
15937
+ getProfileReadme(handle: string): Promise<GithubProfileReadme>;
14642
15938
  }
14643
15939
  }
14644
15940
 
@@ -14971,6 +16267,718 @@ interface GooglePriceGraph {
14971
16267
  }
14972
16268
  }
14973
16269
 
16270
+ declare namespace BowmarkProvider_google_maps {
16271
+ // ── Google Maps — the unit's own declarations, verbatim ──
16272
+ interface SuggestPlacesArgs {
16273
+ query: string;
16274
+ }
16275
+ interface SearchPlacesArgs {
16276
+ query: string;
16277
+ }
16278
+ interface SearchPlacesResult {
16279
+ featureId: string;
16280
+ name: string;
16281
+ address: string;
16282
+ coordinates: { lat: number; lng: number } | null;
16283
+ categories: string[];
16284
+ rating?: number;
16285
+ reviewCount?: number;
16286
+ }
16287
+ interface GeocodeAddressArgs {
16288
+ address: string;
16289
+ }
16290
+ interface GeocodeAddressResult {
16291
+ featureId: string;
16292
+ name: string;
16293
+ formattedAddress: string;
16294
+ coordinates: { lat: number; lng: number } | null;
16295
+ }
16296
+ interface ReverseGeocodeArgs {
16297
+ lat: number;
16298
+ lng: number;
16299
+ }
16300
+ interface ReverseGeocodeResult {
16301
+ formatted: string;
16302
+ plusCode: string;
16303
+ locality: string;
16304
+ dms: string;
16305
+ coordinates: { lat: number; lng: number };
16306
+ }
16307
+ interface GetPlaceArgs {
16308
+ query: string;
16309
+ }
16310
+ interface GetPlaceResult {
16311
+ featureId: string;
16312
+ name: string;
16313
+ address: string;
16314
+ coordinates: { lat: number; lng: number } | null;
16315
+ categories: string[];
16316
+ neighborhood?: string;
16317
+ phone?: string;
16318
+ website?: string;
16319
+ rating?: number;
16320
+ reviewCount?: number;
16321
+ hours?: { day: string; hours: string[] }[];
16322
+ }
16323
+ interface ListReviewsArgs {
16324
+ query: string;
16325
+ }
16326
+ interface Review {
16327
+ author: string;
16328
+ authorId?: string;
16329
+ rating: number;
16330
+ text: string;
16331
+ relativeDate?: string;
16332
+ }
16333
+ interface ListRelatedPlacesArgs {
16334
+ query: string;
16335
+ }
16336
+ interface RelatedPlace {
16337
+ featureId: string;
16338
+ name: string;
16339
+ coordinates: { lat: number; lng: number } | null;
16340
+ categories: string[];
16341
+ rating?: number;
16342
+ reviewCount?: number;
16343
+ }
16344
+ interface GetDirectionsArgs {
16345
+ origin: string;
16346
+ destination: string;
16347
+ mode?: "driving" | "walking" | "transit";
16348
+ }
16349
+ interface DirectionsStep {
16350
+ instruction: string;
16351
+ distance: string;
16352
+ duration: string;
16353
+ }
16354
+ interface GetDirectionsResult {
16355
+ distance: string;
16356
+ duration: string;
16357
+ distanceMeters: number;
16358
+ durationSeconds: number;
16359
+ steps: DirectionsStep[];
16360
+ }
16361
+ interface ResolvePlaceUrlArgs {
16362
+ url: string;
16363
+ }
16364
+ interface GoogleMapsPlace {
16365
+ featureId: string;
16366
+ name?: string;
16367
+ }
16368
+ interface ListPhotosArgs {
16369
+ featureId: string;
16370
+ }
16371
+ interface Photo {
16372
+ url: string;
16373
+ width: number;
16374
+ height: number;
16375
+ takenAt?: string;
16376
+ source?: string;
16377
+ }
16378
+
16379
+ /**
16380
+ * Local business search on Google Maps — find places by what a person would say, then read the
16381
+ * address, hours, rating, reviews, photos, co-located tenants and route. suggestPlaces
16382
+ * (autocomplete), searchPlaces (the door), geocodeAddress, getPlace, listReviews, listPhotos,
16383
+ * listRelatedPlaces, getDirections, resolvePlaceUrl and reverseGeocode are built; everything
16384
+ * else is still a declared stub.
16385
+ */
16386
+ interface Unit {
16387
+ /**
16388
+ * Google Maps' own autocomplete for a half-typed query — what the search box offers while
16389
+ * somebody types. Returns the completed queries, ready to hand to searchPlaces once it lands.
16390
+ */
16391
+ suggestPlaces(args: SuggestPlacesArgs): Promise<string[]>;
16392
+
16393
+ /**
16394
+ * The door every other Maps function chains off. Takes what a person would say — "coffee shops
16395
+ * in Seattle WA", "pizza near Austin TX" — and returns the ranked places Google shows for it:
16396
+ * feature id, name, address, coordinates and categories, plus rating and review count when the
16397
+ * site's response carries them. The location lives in the query text; Google resolves it from
16398
+ * there rather than from a separate coordinate.
16399
+ */
16400
+ searchPlaces(args: SearchPlacesArgs): Promise<SearchPlacesResult[]>;
16401
+
16402
+ /**
16403
+ * A street address, a city, or a business name in — the matching Google Maps place, its
16404
+ * feature id and its coordinates out. Rides the same door as searchPlaces (a second reading of
16405
+ * the same response), so it only resolves a query that names ONE place; a category or
16406
+ * list-style query throws.
16407
+ */
16408
+ geocodeAddress(args: GeocodeAddressArgs): Promise<GeocodeAddressResult>;
16409
+
16410
+ /**
16411
+ * A point in — the Plus Code and locality Google Maps shows for it out, the same string a
16412
+ * person sees when they drop a pin ("JMC2+57W Seattle, Washington"), never a street address:
16413
+ * that is what the site itself answers for a bare point, verified live against the White
16414
+ * House's own coordinates. Rides the same tbm=map door searchPlaces and geocodeAddress use,
16415
+ * with a different field mask — not the browser rung the survey queued this for; the browser
16416
+ * pass that found the field mask was how the shape was discovered, not what the shipped
16417
+ * function needs.
16418
+ */
16419
+ reverseGeocode(args: ReverseGeocodeArgs): Promise<ReverseGeocodeResult>;
16420
+
16421
+ /**
16422
+ * Everything Google Maps shows on one business's panel — name, full address, coordinates,
16423
+ * category, neighborhood, phone, website, rating, review count and weekly hours, each present
16424
+ * only when the site's own response carried it. A THIRD reading of searchPlaces' door: takes
16425
+ * the same resolving query geocodeAddress does (typically a name plus address, since this does
16426
+ * not take a feature id — measured live, neither the raw id nor a cid string resolves through
16427
+ * this door), and throws when the query names a category or list rather than one business.
16428
+ */
16429
+ getPlace(args: GetPlaceArgs): Promise<GetPlaceResult>;
16430
+
16431
+ /**
16432
+ * The reviews Google Maps shows on a business's own panel — up to 5, each with author, star
16433
+ * rating, review text and the site's own relative date. A FOURTH reading of searchPlaces' door
16434
+ * (the same record getPlace reads, one section further in), not the listugcposts route the
16435
+ * survey planned: that route needed a session token minted by a place-page bootstrap that was
16436
+ * never cracked, but the same reviews the token would have fetched are already sitting in the
16437
+ * panel response. Takes the same resolving query getPlace does. Returns [] for a place with no
16438
+ * reviews rather than throwing; throws only when the query itself does not resolve to one
16439
+ * place.
16440
+ */
16441
+ listReviews(args: ListReviewsArgs): Promise<Review[]>;
16442
+
16443
+ /**
16444
+ * Other businesses Google Maps lists "At this place" — the site's own label for a shared
16445
+ * address, not the "people also search for" competitor set the survey planned. A FIFTH reading
16446
+ * of searchPlaces' door (the same record getPlace reads, at [204]). Verified 2026-09-15:
16447
+ * `null` for an ordinary standalone business (confirmed against four, including Analog Coffee
16448
+ * and Pike Place Market), populated only for a multi-tenant venue — Space Needle's own gift
16449
+ * shop, café and lounge; a 61-store list for Westlake Center mall. Returns [] for a
16450
+ * single-business query rather than throwing; throws only when the query itself does not
16451
+ * resolve to one place.
16452
+ */
16453
+ listRelatedPlaces(args: ListRelatedPlacesArgs): Promise<RelatedPlace[]>;
16454
+
16455
+ /**
16456
+ * A DIFFERENT door from searchPlaces' — www.google.com/maps/preview/directions, its own
16457
+ * reusable pb= template (BUILD_QUEUE.md), one per mode. Takes origin and destination as text,
16458
+ * exactly what a person would type ("Space Needle, Seattle, WA") or a
16459
+ * searchPlaces/geocodeAddress result's name plus address — not a feature id, measured live the
16460
+ * same way getPlace measured it. mode defaults to "driving"; "walking" and "transit" are also
16461
+ * built. "bicycling" is not: its response shape diverges enough that a route total cannot be
16462
+ * read off it safely yet. Returns the site's own trip total (distance, duration, traffic-aware
16463
+ * for driving) plus the turn-by-turn instructions, each carrying the site's own distance and
16464
+ * duration text. Throws when either place does not resolve to a route.
16465
+ */
16466
+ getDirections(args: GetDirectionsArgs): Promise<GetDirectionsResult>;
16467
+
16468
+ /**
16469
+ * A Google Maps link somebody pasted — a maps.app.goo.gl short link, a full /maps/place/ link,
16470
+ * or the older ?ftid=/?cid= link — turned into the feature id and name it points at. Two of
16471
+ * the three shapes need no network call at all: everything returned is already sitting in the
16472
+ * URL string, since fetching a resolved link live only echoes the request back rather than
16473
+ * adding data (measured 2026-09-15). Only a short link costs a request — one redirect-follow,
16474
+ * reading the destination out of the "location" header rather than the (contentless) body. A
16475
+ * bare ?cid= link resolves only the LOW half of the feature id and carries no name, reported
16476
+ * as "0x0:0x<lo>" the same way the site's own echo does. Throws when the link resolves to
16477
+ * something that is not a place — a dropped-pin share or a review share, both measured live.
16478
+ */
16479
+ resolvePlaceUrl(args: ResolvePlaceUrlArgs): Promise<GoogleMapsPlace>;
16480
+
16481
+ /**
16482
+ * The photos Google Maps shows in a place's gallery panel — up to 20, each with a url, its
16483
+ * real dimensions and the site's own upload-source tag ("photos:gmm_ios_review_post" and
16484
+ * similar — which app and flow it came in through, not a caption; none was found at any
16485
+ * position tried), plus a date when the response carried one. A THIRD door, not searchPlaces'
16486
+ * field mask: opening the place page's own photo panel fires its own batchexecute RPC, which
16487
+ * is not a bootstrap-derived static template the way searchPlaces' and reverseGeocode's are —
16488
+ * a browser genuinely has to run to get the real gallery back, measured 2026-09-16. Takes a
16489
+ * featureId (searchPlaces/geocodeAddress/getPlace/resolvePlaceUrl all hand one back), not a
16490
+ * resolving query.
16491
+ */
16492
+ listPhotos(args: ListPhotosArgs): Promise<Photo[]>;
16493
+ }
16494
+ }
16495
+
16496
+ declare namespace BowmarkProvider_google_news {
16497
+ // ── Google News — the unit's own declarations, verbatim ──
16498
+ interface GoogleNewsLocaleArg {
16499
+ hl?: string;
16500
+ gl?: string;
16501
+ ceid?: string;
16502
+ }
16503
+ interface GoogleNewsClusterEntry {
16504
+ title: string;
16505
+ link: string;
16506
+ publisher: string;
16507
+ }
16508
+ interface GoogleNewsArticle {
16509
+ articleId: string;
16510
+ title: string;
16511
+ link: string;
16512
+ publisher: string;
16513
+ publisherUrl: string | null;
16514
+ publishedAt: string | null;
16515
+ cluster: GoogleNewsClusterEntry[];
16516
+ }
16517
+ interface GoogleNewsSearchResult {
16518
+ query: string;
16519
+ articles: GoogleNewsArticle[];
16520
+ }
16521
+ interface GoogleNewsTopStories {
16522
+ title: string;
16523
+ clusters: GoogleNewsArticle[];
16524
+ }
16525
+ interface GoogleNewsTopicHeadlines {
16526
+ section: "World" | "Nation" | "Business" | "Technology" | "Entertainment" | "Sports" | "Science" | "Health";
16527
+ title: string;
16528
+ articles: GoogleNewsArticle[];
16529
+ }
16530
+ interface GoogleNewsPublisherHeadlines {
16531
+ publisher: string;
16532
+ query: string;
16533
+ articles: GoogleNewsArticle[];
16534
+ }
16535
+ interface GoogleNewsLocalHeadlines {
16536
+ place: string;
16537
+ title: string;
16538
+ articles: GoogleNewsArticle[];
16539
+ }
16540
+ interface GoogleNewsArticleResolution {
16541
+ articleId: string;
16542
+ url: string;
16543
+ }
16544
+ interface GoogleNewsTopic {
16545
+ topicId: string;
16546
+ name: string;
16547
+ }
16548
+ interface GoogleNewsTopicFeed {
16549
+ topicId: string;
16550
+ title: string;
16551
+ articles: GoogleNewsArticle[];
16552
+ }
16553
+ interface GoogleNewsStory {
16554
+ storyId: string;
16555
+ title: string;
16556
+ }
16557
+ interface GoogleNewsCoverageArticle {
16558
+ articleId: string;
16559
+ title: string;
16560
+ snippet: string | null;
16561
+ publisher: string;
16562
+ publisherUrl: string | null;
16563
+ url: string;
16564
+ publishedAt: string | null;
16565
+ }
16566
+ interface GoogleNewsFullCoverage {
16567
+ storyId: string;
16568
+ articles: GoogleNewsCoverageArticle[];
16569
+ }
16570
+
16571
+ /**
16572
+ * Headlines from every publisher at once — today's top stories as clusters, a section or a
16573
+ * city's local news, one outlet's own coverage, and everything indexed about a subject with
16574
+ * Google's own when: and site: operators. searchNews (the door), topStories,
16575
+ * listTopicHeadlines, listLocalHeadlines, listPublisherHeadlines, resolveArticleUrl (the
16576
+ * redirector-to-publisher resolver every other function's links need), listTopics (the finder
16577
+ * for getTopicHeadlines), listStories (the finder for getFullCoverage) and getFullCoverage
16578
+ * (every outlet reporting one story) are built; everything else is still a declared stub.
16579
+ */
16580
+ interface Unit {
16581
+ /**
16582
+ * Everything Google News has indexed about a subject, across every publisher at once —
16583
+ * headline, publisher, publication time and the Google News link, newest first. `query` is
16584
+ * exactly what a person would type into Google News' own search box, and Google's own
16585
+ * operators work inside it: `when:1h`/`when:1d`/`when:7d` narrows the window,
16586
+ * `site:reuters.com` pins one publisher, quotes pin a phrase and `(a OR b)` unions two
16587
+ * subjects — measured 2026-09-15: `site:reuters.com tesla` returned 100 items of which 100
16588
+ * carried `<source>Reuters</source>`. This is the provider's main door: a caller holding only
16589
+ * words gets in here. A query that matches nothing returns an empty `articles` array rather
16590
+ * than throwing. `locale` — `{ hl, gl, ceid }` — asks for another country/language edition,
16591
+ * e.g. `{ hl: "es-419", gl: "MX", ceid: "MX:es" }` for Mexico; omitted, every field defaults
16592
+ * to the US English edition.
16593
+ */
16594
+ searchNews(query: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsSearchResult>;
16595
+
16596
+ /**
16597
+ * What Google News is leading with right now — the front page, as ranked story CLUSTERS rather
16598
+ * than a flat list. Each entry carries the lead headline and publisher plus every other outlet
16599
+ * covering the same story, which is the one thing a single publisher's own feed can never give
16600
+ * a caller asking "what is everyone saying about this today". `locale` — `{ hl, gl, ceid }` —
16601
+ * asks for another country/language edition, e.g. `{ hl: "es-419", gl: "MX", ceid: "MX:es" }`
16602
+ * for Mexico; omitted, the US English front page.
16603
+ */
16604
+ topStories(locale?: GoogleNewsLocaleArg): Promise<GoogleNewsTopStories>;
16605
+
16606
+ /**
16607
+ * The latest headlines in one of Google News' own eight sections — World, Nation, Business,
16608
+ * Technology, Entertainment, Sports, Science or Health — by section NAME, so a caller who has
16609
+ * only the word "technology" never has to hold an opaque topic id. The name is matched
16610
+ * case-insensitively against the closed list of eight; anything else throws before any request
16611
+ * is made, because an unrecognized section answers 200 with Google News' own app-shell HTML
16612
+ * rather than a 404 (measured 2026-09-15) — reading that as an empty section would be silently
16613
+ * wrong rather than refused. `locale` — `{ hl, gl, ceid }` — asks for another country/language
16614
+ * edition; omitted, the US English one.
16615
+ */
16616
+ listTopicHeadlines(section: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsTopicHeadlines>;
16617
+
16618
+ /**
16619
+ * Everything Google News has indexed from one publisher — `publisher` is a domain like
16620
+ * "reuters.com" or "apnews.com" — newest first, optionally narrowed with `query` the same way
16621
+ * `searchNews` takes one. Built on the search door with a `site:` filter
16622
+ * (`/rss/search?q=site:<publisher> <query>`), NOT on the route that looks like its own:
16623
+ * `/rss/headlines/section/publication/<NAME>` answers 200 with the Top stories feed
16624
+ * byte-for-byte for a name it cannot resolve, so it would look like it worked and be wrong for
16625
+ * every publisher. Measured 2026-09-15: `site:reuters.com tesla` returned 100 items of which
16626
+ * 100 carried a `<source>` domain on `reuters.com`. `locale` — `{ hl, gl, ceid }` — asks for
16627
+ * another country/language edition; omitted, the US English one.
16628
+ */
16629
+ listPublisherHeadlines(publisher: string, query?: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsPublisherHeadlines>;
16630
+
16631
+ /**
16632
+ * What is being reported in one place — the local-news edition for a city or region, by NAME
16633
+ * ("Seattle", "San Francisco"), not a place id. There is no closed list of valid places, so a
16634
+ * place Google News has no edition for is refused only after the request comes back: it
16635
+ * answers 200 with an in-protocol "This feed is not available." sentinel item and a bare
16636
+ * "Google News" channel title rather than the place's own name (measured 2026-09-15 on a
16637
+ * nonsense place; the same sentinel `_client` already drops out of every other feed by guid) —
16638
+ * reading that as an empty result would be silently wrong, so this throws instead. A
16639
+ * recognized place's own channel title is echoed back in `place`, in the site's own spelling,
16640
+ * so `"seattle"` and `"Seattle"` both resolve to `"Seattle"`. `locale` — `{ hl, gl, ceid }` —
16641
+ * asks for another country/language edition; omitted, the US English one.
16642
+ */
16643
+ listLocalHeadlines(place: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsLocalHeadlines>;
16644
+
16645
+ /**
16646
+ * The publisher's real article URL behind a Google News link — every `link` in every feed
16647
+ * above is a `news.google.com/rss/articles/<id>` redirector that does NOT redirect (it 302s to
16648
+ * itself, then serves an interstitial with no publisher URL anywhere in its bytes), so this is
16649
+ * what turns a headline into something a caller can actually read. Takes either the bare
16650
+ * `articleId` (a feed item's own `<guid>`) or a full redirector link someone pasted. Two hops,
16651
+ * both browserless: GET the interstitial for a `data-n-a-id`/`-ts`/`-sg` signature minted for
16652
+ * that article page, then POST it to the site's `batchexecute` RPC for the real URL — the
16653
+ * signature cannot be skipped or reused across articles, so this is always two requests.
16654
+ */
16655
+ resolveArticleUrl(articleIdOrLink: string): Promise<GoogleNewsArticleResolution>;
16656
+
16657
+ /**
16658
+ * The topics Google News' own home-page nav rail is offering today — the eight standing
16659
+ * sections plus "Your local news" (measured 2026-09-15: nine entries, geo-scoped to whichever
16660
+ * exit made the request) — each with the opaque topic id `getTopicHeadlines` takes. Read off
16661
+ * the home page's own embedded `AF_initDataCallback({key: 'ds:2'…})` state rather than scraped
16662
+ * from the rendered nav, so it needs no browser. The finder that makes a topic id reachable by
16663
+ * somebody who only holds words. `locale` — `{ hl, gl, ceid }` — asks for another
16664
+ * country/language edition's own nav rail; omitted, the US English one.
16665
+ */
16666
+ listTopics(locale?: GoogleNewsLocaleArg): Promise<GoogleNewsTopic[]>;
16667
+
16668
+ /**
16669
+ * The headlines under any Google News topic id — the opaque key `/rss/topics/<id>` takes,
16670
+ * which the eight named sections `listTopicHeadlines` takes by word are only a subset of.
16671
+ * Identical fetch and parse to `listTopicHeadlines` (`/rss/topics/<topicId>` rather than
16672
+ * `/rss/headlines/section/topic/<NAME>`) — the only difference is the key, since a topic id
16673
+ * has no canonical spelling for the site to correct it to. Measured 2026-09-15: the Technology
16674
+ * section's own topic id answers the identical feed shape as its section-name door, 70 items,
16675
+ * titled "Technology - Latest - Google News". THE ONLY IDS REACHABLE WITHOUT AN ACCOUNT ARE
16676
+ * THE NINE `listTopics` RETURNS. Google News also runs entity and interest topics (a company,
16677
+ * a person, a sports league), but measured 2026-09-16 nothing logged-out hands their ids out —
16678
+ * a topic page, a story page, `/home` and `/publications` each carry only the nav rail's own
16679
+ * nine, and the HTML `/search` page that renders the entity's Follow chip answers 429 through
16680
+ * the proxy. To follow a company or a person today, use `searchNews`. `locale` — `{ hl, gl,
16681
+ * ceid }` — asks for another country/language edition; omitted, the US English one.
16682
+ */
16683
+ getTopicHeadlines(topicId: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsTopicFeed>;
16684
+
16685
+ /**
16686
+ * The story CLUSTERS Google News is running right now, as ids — the finder for
16687
+ * `getFullCoverage`. Pass a `topicId` (from `listTopics`, or one of the eight section names'
16688
+ * own topic id) to read a topic page — measured 2026-09-15: 43 distinct stories on the
16689
+ * Technology topic page, the richer of the two doors — or omit it to read the front page
16690
+ * instead, which surfaces far fewer (2 measured) since most front-page items are
16691
+ * single-outlet. Reads the "Full Coverage" anchor Google News renders on every multi-outlet
16692
+ * story directly off the page's HTML, rather than the page's own embedded state — no RSS feed
16693
+ * on this site emits a story id at all, so this is the only door. `locale` — `{ hl, gl, ceid
16694
+ * }` — asks for another country/language edition of whichever page is read; omitted, the US
16695
+ * English one.
16696
+ */
16697
+ listStories(topicId?: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsStory[]>;
16698
+
16699
+ /**
16700
+ * Every outlet reporting one story — Google News' own Full Coverage, chained off a `storyId`
16701
+ * from `listStories`. Reads the story page's own `AF_initDataCallback({key: 'ds:0'…})` state:
16702
+ * a mix of named groups ("Top news", "Personal perspective", an occasional "Posts on X" of
16703
+ * social posts rather than articles, which are excluded) and ungrouped rows, folded into one
16704
+ * flat list. Unlike every other function here, each article's `url` is the PUBLISHER's own
16705
+ * page directly — no `news.google.com` redirector, so no `resolveArticleUrl` hop is needed. A
16706
+ * story id is as short-lived as a headline; hold one only as long as the `listStories` call
16707
+ * that produced it — a stale id throws, naming that as the likely cause, rather than answering
16708
+ * with 0 articles. `locale` — `{ hl, gl, ceid }` — matters here even though every article
16709
+ * already carries its own publisher URL: the STORY PAGE ITSELF is read in whichever edition is
16710
+ * asked for, and reading it in the wrong one silently truncates or empties the coverage
16711
+ * (measured 2026-09-16: the same story id answered 0 articles under the US default and 53
16712
+ * under `{ hl: "es-419", gl: "MX", ceid: "MX:es" }`). Pass the SAME locale the `listStories`
16713
+ * call that produced this id used; omitted, the US English edition.
16714
+ */
16715
+ getFullCoverage(storyId: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsFullCoverage>;
16716
+ }
16717
+ }
16718
+
16719
+ declare namespace BowmarkProvider_google_translate {
16720
+ // ── Google Translate — the unit's own declarations, verbatim ──
16721
+ interface TranslateArgs {
16722
+ text: string | readonly string[];
16723
+ to: string;
16724
+ from?: string;
16725
+ }
16726
+ interface GoogleTranslateResult {
16727
+ source: string;
16728
+ translated: string;
16729
+ targetLanguage: string;
16730
+ sourceLanguage: string;
16731
+ detected: boolean;
16732
+ }
16733
+ interface DetectLanguageArgs {
16734
+ text: string;
16735
+ }
16736
+ interface GoogleTranslateLanguageCandidate {
16737
+ language: string;
16738
+ confidence: number;
16739
+ }
16740
+ interface GoogleTranslateLanguageDetection {
16741
+ language: string;
16742
+ confidence: number;
16743
+ candidates: GoogleTranslateLanguageCandidate[];
16744
+ }
16745
+ interface ListLanguagesArgs {
16746
+ hl?: string;
16747
+ }
16748
+ interface GoogleTranslateLanguage {
16749
+ code: string;
16750
+ name: string;
16751
+ sourceSupported: boolean;
16752
+ targetSupported: boolean;
16753
+ }
16754
+ interface LookupWordArgs {
16755
+ word: string;
16756
+ to: string;
16757
+ from: string;
16758
+ hl?: string;
16759
+ }
16760
+ interface GoogleTranslateWordCandidate {
16761
+ word: string;
16762
+ reverseTranslations: string[];
16763
+ score: number;
16764
+ }
16765
+ interface GoogleTranslateWordSense {
16766
+ partOfSpeech: string;
16767
+ candidates: GoogleTranslateWordCandidate[];
16768
+ }
16769
+ interface GoogleTranslateWordLookup {
16770
+ word: string;
16771
+ targetLanguage: string;
16772
+ sourceLanguage: string;
16773
+ senses: GoogleTranslateWordSense[];
16774
+ }
16775
+ interface GetDefinitionsArgs {
16776
+ word: string;
16777
+ language: string;
16778
+ }
16779
+ interface GoogleTranslateDefinitionExample {
16780
+ text: string;
16781
+ }
16782
+ interface GoogleTranslateDefinition {
16783
+ definitionId: string;
16784
+ gloss: string;
16785
+ examples: GoogleTranslateDefinitionExample[];
16786
+ subject?: string[];
16787
+ register?: string[];
16788
+ }
16789
+ interface GoogleTranslateDefinitionSense {
16790
+ partOfSpeech: string;
16791
+ definitions: GoogleTranslateDefinition[];
16792
+ }
16793
+ interface GoogleTranslateWordDefinitions {
16794
+ word: string;
16795
+ language: string;
16796
+ senses: GoogleTranslateDefinitionSense[];
16797
+ }
16798
+ interface GetSynonymsArgs {
16799
+ word: string;
16800
+ language: string;
16801
+ }
16802
+ interface GoogleTranslateSynonymGroup {
16803
+ definitionId: string;
16804
+ synonyms: string[];
16805
+ register?: string[];
16806
+ }
16807
+ interface GoogleTranslateSynonymSense {
16808
+ partOfSpeech: string;
16809
+ groups: GoogleTranslateSynonymGroup[];
16810
+ }
16811
+ interface GoogleTranslateWordSynonyms {
16812
+ word: string;
16813
+ language: string;
16814
+ senses: GoogleTranslateSynonymSense[];
16815
+ }
16816
+ interface GetAlternativeTranslationsArgs {
16817
+ text: string;
16818
+ to: string;
16819
+ from?: string;
16820
+ }
16821
+ interface GoogleTranslateAlternative {
16822
+ text: string;
16823
+ backends: number[];
16824
+ }
16825
+ interface GoogleTranslateAlternativeSegment {
16826
+ sourceSegment: string;
16827
+ offsets: { begin: number; end: number };
16828
+ alternatives: GoogleTranslateAlternative[];
16829
+ }
16830
+ interface GoogleTranslateAlternativeTranslations {
16831
+ text: string;
16832
+ targetLanguage: string;
16833
+ sourceLanguage: string;
16834
+ segments: GoogleTranslateAlternativeSegment[];
16835
+ }
16836
+ interface CheckSpellingArgs {
16837
+ text: string;
16838
+ language: string;
16839
+ }
16840
+ interface GoogleTranslateSpellCheck {
16841
+ text: string;
16842
+ language: string;
16843
+ correct: boolean;
16844
+ corrected?: string;
16845
+ correctedHtml?: string;
16846
+ correctionType?: number[];
16847
+ confident?: boolean;
16848
+ }
16849
+ interface RomanizeArgs {
16850
+ text: string;
16851
+ to: string;
16852
+ from?: string;
16853
+ }
16854
+ interface GoogleTranslateRomanization {
16855
+ text: string;
16856
+ targetLanguage: string;
16857
+ sourceLanguage: string;
16858
+ detected: boolean;
16859
+ targetRomanization?: string;
16860
+ sourceRomanization?: string;
16861
+ }
16862
+ interface SpeakArgs {
16863
+ text: string;
16864
+ language: string;
16865
+ }
16866
+ interface GoogleTranslateSpeech {
16867
+ audioBase64: string;
16868
+ contentType: string;
16869
+ chunkCount: number;
16870
+ }
16871
+
16872
+ /**
16873
+ * Translate text into any of 249 languages, in a batch if you have a list, and find out what
16874
+ * language something already is — plus the dictionary underneath: senses, definitions,
16875
+ * synonyms, alternative wordings, the romanization and the spoken audio. `translate` is built;
16876
+ * everything else is still a declared stub.
16877
+ */
16878
+ interface Unit {
16879
+ /**
16880
+ * Turn text into another language. `args.text` is one string or a list translated together in
16881
+ * one request, in order; `args.to` names the target language by name ("Spanish") or code
16882
+ * ("es", "pt-BR"); `args.from` is optional and, left out, the source is detected per string,
16883
+ * with `detected: true` and the detected code coming back on each result. Returns one
16884
+ * `GoogleTranslateResult` per input string, aligned by position.
16885
+ */
16886
+ translate(args: TranslateArgs): Promise<GoogleTranslateResult[]>;
16887
+
16888
+ /**
16889
+ * Work out what language a string is written in. Returns `language` (Google's own code) and
16890
+ * `confidence` (0-1) rather than swallowing it — a single word can come back confidently wrong
16891
+ * (measured 2026-09-15: "Bonjour" alone detects as "en"), so a caller reading only `language`
16892
+ * cannot tell a guess from a sure thing. `candidates` carries every language Google's detector
16893
+ * considered, most confident first.
16894
+ */
16895
+ detectLanguage(args: DetectLanguageArgs): Promise<GoogleTranslateLanguageDetection>;
16896
+
16897
+ /**
16898
+ * Every language this site supports — the table that turns a caller's "Portuguese" into the
16899
+ * `pt`/`pt-BR` code the rest of this provider takes, and the honest answer to "can Google
16900
+ * Translate do Cherokee". `args.hl` optionally localizes the returned `name`s (`{ hl: "es" }`
16901
+ * returns "abjasio" for `ab`); left out, names come back in English.
16902
+ * `sourceSupported`/`targetSupported` are not both always true — `sl` alone carries `"auto"`
16903
+ * ("Detect language") and `tl` alone carries `"zh-TW"`, measured 2026-09-15.
16904
+ */
16905
+ listLanguages(args?: ListLanguagesArgs): Promise<GoogleTranslateLanguage[]>;
16906
+
16907
+ /**
16908
+ * The full "translations of <word>" dictionary panel: every part of speech Google has for
16909
+ * `args.word`, the candidate translations under each (ordered by Google's own frequency
16910
+ * `score`), and for each candidate the words it itself translates back to — the difference
16911
+ * between "run means correr" and knowing `ejecutar` is the software sense and `huir` is the
16912
+ * fleeing sense. `args.from` is required, unlike `translate` — there is no "detect it" reading
16913
+ * of a dictionary lookup. `senses` comes back empty when Google has no per-sense breakdown for
16914
+ * the term (a longer phrase, or a string its dictionary does not recognize); the plain
16915
+ * `translate` function still works on those.
16916
+ */
16917
+ lookupWord(args: LookupWordArgs): Promise<GoogleTranslateWordLookup>;
16918
+
16919
+ /**
16920
+ * What `args.word` MEANS, IN `args.language` — monolingual, unlike `lookupWord`, which
16921
+ * translates between two. Groups every sense by part of speech, each carrying a plain-English
16922
+ * gloss and, where Google has one, a real usage example (its own `<b>`-highlight markup
16923
+ * stripped). `senses` comes back empty when Google's dictionary has nothing for the term.
16924
+ */
16925
+ getDefinitions(args: GetDefinitionsArgs): Promise<GoogleTranslateWordDefinitions>;
16926
+
16927
+ /**
16928
+ * Other words that mean the same thing as `args.word`, IN `args.language` — grouped by sense
16929
+ * (`definitionId` matches a `GoogleTranslateDefinition.definitionId` from `getDefinitions`)
16930
+ * rather than thrown into one list, and labelled where Google knows the register: "informal"
16931
+ * synonyms for "run" (belt, zip, leg it, hotfoot it) come back in a separate group from the
16932
+ * neutral ones (sprint, race, dart, dash), and a group with no `register` is the neutral case.
16933
+ * `senses` comes back empty when Google has no synonyms for the term.
16934
+ */
16935
+ getSynonyms(args: GetSynonymsArgs): Promise<GoogleTranslateWordSynonyms>;
16936
+
16937
+ /**
16938
+ * The other ways Google would have translated `args.text` — the list that appears when a
16939
+ * person clicks a translated phrase to see what else it could have said. Works on a whole
16940
+ * sentence, not just a word: `args.text` splits into `segments`, one per sentence Google
16941
+ * recognizes, each carrying its own `alternatives` — the unit of the answer is the SEGMENT,
16942
+ * never the whole input. `args.from` is optional and, left out, the source is detected, same
16943
+ * as `translate`.
16944
+ */
16945
+ getAlternativeTranslations(args: GetAlternativeTranslationsArgs): Promise<GoogleTranslateAlternativeTranslations>;
16946
+
16947
+ /**
16948
+ * Google Translate's own "Did you mean …" line for `args.text`, written in `args.language` —
16949
+ * `correct: true` when nothing needed fixing, otherwise the corrected text plain and
16950
+ * HTML-marked-up. What a caller runs before trusting a translation of something a human typed
16951
+ * in a hurry.
16952
+ */
16953
+ checkSpelling(args: CheckSpellingArgs): Promise<GoogleTranslateSpellCheck>;
16954
+
16955
+ /**
16956
+ * A Latin-alphabet (or phonetic) rendering of `args.text` or its translation —
16957
+ * "Ohayōgozaimasu, ogenkidesuka?" under a Japanese translation, "rən" under the English word
16958
+ * "run". `targetRomanization` comes back when the TARGET script is non-Latin,
16959
+ * `sourceRomanization` when the SOURCE is — measured 2026-09-16, that includes a short
16960
+ * Latin-script dictionary lookup, which still carries an English pronunciation guide. Both are
16961
+ * absent on an ordinary sentence between two Latin-script languages, which is a normal answer,
16962
+ * not a failure. `args.from` is optional and, left out, the source is detected, same as
16963
+ * `translate`.
16964
+ */
16965
+ romanize(args: RomanizeArgs): Promise<GoogleTranslateRomanization>;
16966
+
16967
+ /**
16968
+ * Hear `args.text` spoken in `args.language`, as the MP3 the site's own speaker button plays.
16969
+ * Google's `/translate_tts` refuses anything over 200 characters with a hard 400, so this
16970
+ * function chunks longer text on SENTENCE boundaries (never mid-sentence) and stitches the
16971
+ * resulting MP3s into one file — confirmed 2026-09-16 that concatenating raw `/translate_tts`
16972
+ * bytes decodes as one continuous, correctly-timed clip, since the door answers a bare MPEG
16973
+ * stream with no container. `chunkCount` says how many `/translate_tts` calls the answer is
16974
+ * built from. Throws when a single SENTENCE in `args.text` is itself over 200 characters —
16975
+ * there is no boundary left to chunk on, and truncating it silently is the one thing this
16976
+ * function must not do.
16977
+ */
16978
+ speak(args: SpeakArgs): Promise<GoogleTranslateSpeech>;
16979
+ }
16980
+ }
16981
+
14974
16982
  declare namespace BowmarkProvider_gostoreit {
14975
16983
  // ── Go Store It — the unit's own declarations, verbatim ──
14976
16984
  interface GetFacilityUnitsArgs { facilityUrl: string; }
@@ -15608,6 +17616,14 @@ interface HavenPricingProgram {
15608
17616
 
15609
17617
  interface HavenPricingProgramsResult { programs: HavenPricingProgram[] }
15610
17618
 
17619
+ interface HavenListPricingProgramsResult {
17620
+ property: HavenPropertyDetails;
17621
+ state: string | null; // read off the caller's own address, e.g. "CA"
17622
+ programs: HavenPricingProgram[]; // filtered to what `state` qualifies for
17623
+ }
17624
+
17625
+ interface HavenListPricingProgramsArgs { address: string }
17626
+
15611
17627
  /**
15612
17628
  * Haven Energy home battery quoting — read a US address's own property attributes (home size,
15613
17629
  * county, energy-community status) the way Haven's /quote flow does, and read the site's own
@@ -15633,6 +17649,16 @@ interface HavenPricingProgramsResult { programs: HavenPricingProgram[] }
15633
17649
  * county/utility context to narrow to the programs a specific home actually qualifies for.
15634
17650
  */
15635
17651
  getPricingPrograms(): Promise<HavenPricingProgramsResult>;
17652
+
17653
+ /**
17654
+ * One call for the question getPropertyDetails + getPricingPrograms need composing to answer:
17655
+ * which of Haven's active programs does THIS address actually qualify for. Reads the property
17656
+ * attributes and the full program table (the same two live calls the two other functions make)
17657
+ * and filters to the state parsed out of the address string. `state` is null and `programs` is
17658
+ * the full unfiltered table when no 2-letter state code could be read from the address —
17659
+ * Haven's own property-details response never returns one to fall back on.
17660
+ */
17661
+ listPricingPrograms(arg0: HavenListPricingProgramsArgs): Promise<HavenListPricingProgramsResult>;
15636
17662
  }
15637
17663
  }
15638
17664
 
@@ -15697,6 +17723,32 @@ interface HaydenhomesSearchFilters {
15697
17723
  }
15698
17724
  }
15699
17725
 
17726
+ declare namespace BowmarkProvider_hccts {
17727
+ // ── hccts.org Online Application Appointment Booking — the unit's own declarations, verbatim ──
17728
+ interface ApplicationStatus {
17729
+ available: boolean;
17730
+ formUrl: string;
17731
+ message: string;
17732
+ lastChecked: string;
17733
+ }
17734
+
17735
+ interface CheckApplicationAvailabilityArgs {
17736
+ refresh?: boolean;
17737
+ }
17738
+
17739
+ /**
17740
+ * Checks application availability and appointment scheduling for Highlands' adult education
17741
+ * programs.
17742
+ */
17743
+ interface Unit {
17744
+ /**
17745
+ * Checks if the HCCTS online application form is currently accessible and returns the
17746
+ * application status.
17747
+ */
17748
+ checkApplicationAvailability(args: CheckApplicationAvailabilityArgs): Promise<ApplicationStatus>;
17749
+ }
17750
+ }
17751
+
15700
17752
  declare namespace BowmarkProvider_healthcare_gov {
15701
17753
  // ── HealthCare.gov — the unit's own declarations, verbatim ──
15702
17754
  interface healthcare_govPlan {
@@ -19229,12 +21281,14 @@ interface KeepaProduct { asin: string; domainId: number; title: string; csv?: un
19229
21281
 
19230
21282
  /**
19231
21283
  * Keepa's documented Amazon product API — reads a product's native price history and metadata
19232
- * by ASIN. Requires a caller-provided Keepa API key.
21284
+ * by ASIN. Uses Bowmark's Keepa key and charges each request to your account; send your own
21285
+ * key as the `x-bowmark-vendor-key-keepa` header to spend your own Keepa tokens instead.
19233
21286
  */
19234
21287
  interface Unit {
19235
21288
  /**
19236
21289
  * Reads Keepa's native Amazon product record and compact price-history series for one ASIN.
19237
- * Requires a caller-provided Keepa API key.
21290
+ * Uses Bowmark's Keepa key and charges each request to your account; send your own key as the
21291
+ * `x-bowmark-vendor-key-keepa` header to spend your own Keepa tokens instead.
19238
21292
  */
19239
21293
  getProduct(args: { asin: string; domain?: number; stats?: number }): Promise<KeepaProductResult>;
19240
21294
  }
@@ -20627,7 +22681,7 @@ interface LululemonProductAttributes {
20627
22681
  /** The site's own ProductGroup category, e.g. "Leggings". */
20628
22682
  category: string | null;
20629
22683
  description: string | null;
20630
- /** Trademarked fabric names off the detail accordion, e.g. ["Nulu"]. */
22684
+ /** Trademarked fabric names off the product-detail region, e.g. ["Nulu"]. */
20631
22685
  fabrics: string[];
20632
22686
  fit: string | null;
20633
22687
  /** "High-Rise" / "Mid-Rise" / "Low-Rise", as the title spells it. */
@@ -24895,6 +26949,357 @@ interface PremierbuildingsDealer {
24895
26949
  }
24896
26950
  }
24897
26951
 
26952
+ declare namespace BowmarkProvider_prime_video {
26953
+ // ── Prime Video — the unit's own declarations, verbatim ──
26954
+ interface PrimeVideoTitle {
26955
+ titleId: string;
26956
+ catalogId: string | null;
26957
+ title: string;
26958
+ url: string;
26959
+ entityType: string | null;
26960
+ releaseYear: number | null;
26961
+ maturityRating: string | null;
26962
+ entitled: boolean;
26963
+ watchMessage: string | null;
26964
+ }
26965
+ interface PrimeVideoTitleSuggestion {
26966
+ value: string;
26967
+ }
26968
+ interface PrimeVideoWatchOffer {
26969
+ kind: "rent" | "buy" | "subscribe";
26970
+ label: string;
26971
+ price: { currency: string; value: string } | null;
26972
+ quality: "SD" | "HD" | "UHD" | null;
26973
+ channel: { benefitId: string; link: string } | null;
26974
+ }
26975
+ interface PrimeVideoWatchOptions {
26976
+ titleId: string;
26977
+ entitlementType: "Entitled" | "Unentitled";
26978
+ entitled: boolean;
26979
+ message: string;
26980
+ channel: { name: string; link: string } | null;
26981
+ offers: PrimeVideoWatchOffer[];
26982
+ }
26983
+ interface PrimeVideoSeason {
26984
+ seasonId: string;
26985
+ seasonLink: string;
26986
+ displayName: string;
26987
+ sequenceNumber: number;
26988
+ seasonSelectorIcon: string | null;
26989
+ }
26990
+ interface PrimeVideoCredit {
26991
+ name: string;
26992
+ searchLink: string | null;
26993
+ }
26994
+ interface PrimeVideoRatingBucket {
26995
+ stars: 1 | 2 | 3 | 4 | 5;
26996
+ percentage: number;
26997
+ }
26998
+ interface PrimeVideoTitleDetail {
26999
+ titleId: string;
27000
+ catalogId: string | null;
27001
+ title: string;
27002
+ seriesTitle: string | null;
27003
+ seasonNumber: number | null;
27004
+ titleType: string | null;
27005
+ synopsis: string | null;
27006
+ releaseYear: number | null;
27007
+ releaseDate: string | null;
27008
+ runtime: string | null;
27009
+ genres: string[];
27010
+ maturityRating: string | null;
27011
+ cast: PrimeVideoCredit[];
27012
+ directors: PrimeVideoCredit[];
27013
+ studios: string[];
27014
+ amazonRating: { value: number; count: number } | null;
27015
+ ratingsHistogram: PrimeVideoRatingBucket[];
27016
+ imdbScore: number | null;
27017
+ audioTracks: string[];
27018
+ subtitles: string[];
27019
+ isUhd: boolean;
27020
+ isHdr: boolean;
27021
+ isDolbyVision: boolean;
27022
+ isDolbyAtmos: boolean;
27023
+ isXRay: boolean;
27024
+ isClosedCaption: boolean;
27025
+ isPrime: boolean;
27026
+ isAd: boolean;
27027
+ }
27028
+ interface PrimeVideoEpisode {
27029
+ titleId: string | null;
27030
+ episodeNumber: number;
27031
+ title: string;
27032
+ synopsis: string | null;
27033
+ runtime: string | null;
27034
+ durationSeconds: number | null;
27035
+ releaseDate: string | null;
27036
+ releaseYear: number | null;
27037
+ images: { packshot: string | null; covershot: string | null };
27038
+ audioTracks: string[];
27039
+ subtitles: string[];
27040
+ isUhd: boolean;
27041
+ isHdr: boolean;
27042
+ isDolbyVision: boolean;
27043
+ isDolbyAtmos: boolean;
27044
+ isXRay: boolean;
27045
+ isClosedCaption: boolean;
27046
+ isPrime: boolean;
27047
+ isAd: boolean;
27048
+ }
27049
+ interface PrimeVideoCategory {
27050
+ name: string;
27051
+ slug: string;
27052
+ kind: "genre" | "collection" | "storefront";
27053
+ path: string;
27054
+ }
27055
+ interface PrimeVideoCategoryRow {
27056
+ heading: string;
27057
+ titles: PrimeVideoTitle[];
27058
+ }
27059
+ interface PrimeVideoTop10Entry extends PrimeVideoTitle {
27060
+ position: number;
27061
+ list: "tv" | "movies" | "channel";
27062
+ }
27063
+ interface PrimeVideoChannel {
27064
+ name: string;
27065
+ channelId: string | null;
27066
+ benefitId: string | null;
27067
+ synopsis: string | null;
27068
+ offerMessage: string | null;
27069
+ }
27070
+ interface PrimeVideoChannelDetail {
27071
+ name: string;
27072
+ rows: PrimeVideoCategoryRow[];
27073
+ }
27074
+ interface PrimeVideoLiveProgram {
27075
+ title: string;
27076
+ seriesTitle: string | null;
27077
+ start: number;
27078
+ end: number;
27079
+ }
27080
+ interface PrimeVideoLiveStation {
27081
+ id: string;
27082
+ name: string;
27083
+ logo: string | null;
27084
+ group: string;
27085
+ nowPlaying: PrimeVideoLiveProgram | null;
27086
+ }
27087
+
27088
+ /**
27089
+ * Search Prime Video's catalogue and read a film or series the way a viewer does — synopsis,
27090
+ * cast, rating, seasons and episodes — and above all say how it can actually be watched:
27091
+ * included with Prime, free with ads, on a named add-on channel, or rentable and buyable with
27092
+ * the real price. Plus the browse surfaces (genres, collections, the top ten, this week's
27093
+ * deals), the add-on channels, and the free live TV, news and sports schedules. searchTitles,
27094
+ * suggestTitles, getTitle, getWatchOptions, listSeasons, listEpisodes and listCategories are
27095
+ * built; everything else is still a declared stub.
27096
+ */
27097
+ interface Unit {
27098
+ /**
27099
+ * Search Prime Video's whole catalogue for what a person would type — "matrix", "the boys" —
27100
+ * and get back the title cards the site itself ranks: display title, the titleId every other
27101
+ * function here takes, whether it is a film or a series, the year, the maturity rating, and
27102
+ * the site's own sentence for how to watch it. THE provider's door: every titleId-taking
27103
+ * function below is fed by this one. Returns the FIRST page only — Prime Video's search page
27104
+ * carries no pagination markers at all (measured 2026-09-15) — and the site's six refinement
27105
+ * filters (film-or-series, how you can watch it, which channel, HD/UHD, theme, audio language)
27106
+ * are not built here: they ride an opaque per-page `serviceToken`, not a query parameter, and
27107
+ * a query parameter silently returns the unfiltered set rather than erroring. A query that
27108
+ * matches nothing returns an empty array rather than throwing.
27109
+ */
27110
+ searchTitles(query: string): Promise<PrimeVideoTitle[]>;
27111
+
27112
+ /**
27113
+ * Ask Prime Video's own search box what it would autocomplete a prefix to — "the boy" comes
27114
+ * back as "the boys", "the boy", "the boy and the heron". What an agent holding a
27115
+ * half-remembered title calls before it commits to a search, and the cheapest call in the
27116
+ * provider.
27117
+ */
27118
+ suggestTitles(prefix: string): Promise<PrimeVideoTitleSuggestion[]>;
27119
+
27120
+ /**
27121
+ * Read one film, series-season or episode the way a viewer reads its page: title, synopsis,
27122
+ * year, release date, runtime, genres, maturity rating, cast, directors, studio, the Amazon
27123
+ * customer rating and its five-star histogram, the IMDb score, which audio languages and
27124
+ * subtitles it ships, and whether it is in UHD, HDR, Dolby Atmos or X-Ray. The core read of
27125
+ * the whole provider. Takes a titleId or a title URL, e.g. one read off searchTitles(). THE
27126
+ * REVIEW TEXT IS NOT HERE — the aggregate rating and histogram are real and logged out, but
27127
+ * review bodies are amazon.com's own surface behind amazon.com's sign-in wall.
27128
+ */
27129
+ getTitle(titleId: string): Promise<PrimeVideoTitleDetail>;
27130
+
27131
+ /**
27132
+ * Say how you would actually watch a title: included with your Prime membership, free with
27133
+ * ads, on an add-on channel you would have to subscribe to (and which one), or available to
27134
+ * rent or buy — and when it is rent-or-buy, every offer with its real price and quality. THE
27135
+ * question this provider exists to answer, and the one no general search result answers about
27136
+ * Amazon's catalogue. Takes a titleId or a title URL, e.g. one read off searchTitles() or
27137
+ * getTitle(). Reads the SAME page as getTitle, never fetches it twice. Placing any of these
27138
+ * orders is never a function of this provider — a flow that costs money stops before the
27139
+ * payment step, always.
27140
+ */
27141
+ getWatchOptions(titleId: string): Promise<PrimeVideoWatchOptions>;
27142
+
27143
+ /**
27144
+ * List every season of a series with the titleId that opens each one, its number, its display
27145
+ * name, and whether it needs paying for beyond what the current season needs. What an agent
27146
+ * needs when the person said "season 4" and the search returned whichever season Prime Video
27147
+ * ranked first. Takes a titleId or a title URL, e.g. one read off searchTitles() or
27148
+ * getTitle(). Reads the SAME cached page as getTitle and getWatchOptions, never fetches it
27149
+ * twice. A film returns an empty array — a real, measured answer, since a film's own /detail/
27150
+ * page carries no seasons at all.
27151
+ */
27152
+ listSeasons(titleId: string): Promise<PrimeVideoSeason[]>;
27153
+
27154
+ /**
27155
+ * List a season's episodes with number, title, synopsis, runtime, release date, artwork, and
27156
+ * the audio and subtitle languages each one ships. The read behind "what happens in episode 3"
27157
+ * and "how long is the finale". Takes the SEASON's titleId — one read off listSeasons() or
27158
+ * getTitle() — or a title URL. Reads the SAME cached page as getTitle, getWatchOptions and
27159
+ * listSeasons, never fetches it twice; episodes come with whichever season is selected, so
27160
+ * reading another season means calling this on THAT season's own titleId, off listSeasons(). A
27161
+ * film returns an empty array — a real, measured answer, matching listSeasons() on the same
27162
+ * title.
27163
+ */
27164
+ listEpisodes(titleId: string): Promise<PrimeVideoEpisode[]>;
27165
+
27166
+ /**
27167
+ * List the ways Prime Video lets you browse — its genres (action, comedy, horror, anime,
27168
+ * documentary and more, plus kids), its editorial collections (new and upcoming, award
27169
+ * winners, free to watch) and its storefronts (movies, TV, store, sports, news, live TV,
27170
+ * subscriptions) — each with the token the browse function below this one in the queue takes.
27171
+ * The door for every browse read here: an agent holding the word "horror" can reach a real
27172
+ * listing without being told a URL. Every row carries `name` (the site's own display text),
27173
+ * `slug` (the literal, inconsistently-cased path token — "science-fiction", "mgForYou" — never
27174
+ * guess its casing) and `kind`. Resolve a caller's typed word against `name`, never `slug`.
27175
+ */
27176
+ listCategories(): Promise<PrimeVideoCategory[]>;
27177
+
27178
+ /**
27179
+ * Browse one genre, collection or storefront and get its rows of titles back — "what horror is
27180
+ * on Prime Video", "what is in the free-with-ads collection" — each row carrying the site's
27181
+ * own heading ("Popular movies", "Free comedy movies") and every title under it in the site's
27182
+ * own order, with the same fields searchTitles() returns. Takes a `path` off listCategories(),
27183
+ * e.g. "/genre/comedy", "/collection/streamfree", "/movie", "/tv" or "/store" — those five are
27184
+ * the only shapes this pass measured. Drops the leading, unheaded hero carousel every
27185
+ * storefront page opens with; every other row is real. Returns the FIRST page only, exactly
27186
+ * like searchTitles() — these pages carry no pagination markers either.
27187
+ */
27188
+ listCategoryTitles(path: string): Promise<PrimeVideoCategoryRow[]>;
27189
+
27190
+ /**
27191
+ * What has just arrived on Prime Video and what is coming — the read behind "anything new
27192
+ * worth watching", which a genre browse can never answer because a genre ranks by popularity
27193
+ * and this ranks by recency. Same row shape as listCategoryTitles(): a heading ("Premium New
27194
+ * Releases", "Recently added to Prime – Movies") and every title under it. No arguments — this
27195
+ * is a named call over listCategoryTitles' own parser, pointed at the site's own newness
27196
+ * surfaces (`/collection/newandupcoming` plus `/tv`'s "Explore: Latest TV" row) rather than a
27197
+ * caller-supplied path. Prime Video publishes no logged-out "leaving soon" surface — none of
27198
+ * "leaving", "expires", "available until" or "last chance" appear anywhere the survey read —
27199
+ * so there is no sibling function for that half of the question.
27200
+ */
27201
+ listNewReleases(): Promise<PrimeVideoCategoryRow[]>;
27202
+
27203
+ /**
27204
+ * What you can watch on Prime Video without paying anything at all — the free-with-ads
27205
+ * catalogue, a different answer from "included with Prime" and the honest one for a caller
27206
+ * with no Amazon subscription. No arguments — `GET /collection/streamfree`, filtered
27207
+ * card-by-card to the site's own `freewithads` entitlement marker rather than trusted by row
27208
+ * heading: a "Free popular TV" row on that page mixes titles a visitor with no subscription
27209
+ * can watch with titles that need Prime, and both carry the identical "Watch for free" message
27210
+ * and "Entitled" verdict, so the row heading alone cannot tell them apart (measured
27211
+ * 2026-09-16: 8 of 20 cards on that row are Prime-included, not free-with-ads). A row whose
27212
+ * cards are all Prime-included, not free-with-ads, is dropped rather than returned empty.
27213
+ */
27214
+ listFreeToWatch(): Promise<PrimeVideoCategoryRow[]>;
27215
+
27216
+ /**
27217
+ * Prime Video's own top ten right now — the most-watched TV shows in the US ("tv", off `/tv`),
27218
+ * the top films to rent or buy ("movies", off `/store`), or the top ten on one add-on channel
27219
+ * ("channel", off that channel's own page — pass its uuid as `channelId`, e.g. one read off
27220
+ * listChannels() or a channel URL). The read behind "what is everyone watching", and one
27221
+ * search can never give you, because search ranks by relevance and this ranks by what is
27222
+ * actually being played. Every row carries `position` (the card's own 1-based rank within that
27223
+ * list — Prime Video never prints a rank number, so this is the card's own order) and `list`
27224
+ * (which of the three it came from) alongside the same fields searchTitles() returns; a merged
27225
+ * top ten that does not say whether it means streaming or renting is a wrong answer wearing a
27226
+ * right one. **The row is intermittent** — measured this build pass, three spaced captures of
27227
+ * `/tv` in one minute carried it on only one — so a request that lands without it returns
27228
+ * `[]`, a real and honest answer, never an error.
27229
+ */
27230
+ listTop10(list: "tv" | "movies" | "channel", channelId?: string): Promise<PrimeVideoTop10Entry[]>;
27231
+
27232
+ /**
27233
+ * What is discounted to rent or buy on Prime Video this week — "Prime deals this week", "New
27234
+ * release deals", time-boxed sales and film bundles — the read behind "how do I watch this"
27235
+ * when the answer turns out to be "buy it" and the follow-up is "is it cheaper right now". No
27236
+ * arguments — `GET /store/deals`, read with the same listCategoryTitles() parser: same row
27237
+ * shape (a heading and every title under it), same dropped leading hero carousel. **Carries no
27238
+ * price.** Exactly three dollar strings exist on the whole page and all three are a row
27239
+ * heading ("$15.99 or less TV deals"), never a per-title price, so a caller who wants the
27240
+ * number calls getWatchOptions() on a titleId from one of these rows, where the price comes
27241
+ * off a decoded offerToken rather than a scraped string.
27242
+ */
27243
+ listDeals(): Promise<PrimeVideoCategoryRow[]>;
27244
+
27245
+ /**
27246
+ * List the add-on subscriptions Prime Video sells inside itself — HBO Max, Paramount+,
27247
+ * Britbox, ViX Premium and seventy-odd more — with the two ids each one is addressed by:
27248
+ * `channelId`, which opens the channel's own page (getChannel(), listTop10("channel",
27249
+ * channelId)), and `benefitId`, which `GET /offers?benefitId=<benefitId>` takes to start a
27250
+ * subscription. The door for getChannel() and the thing that turns getWatchOptions' "get an
27251
+ * add-on subscription" into a named service a person can decide about. No arguments — `GET
27252
+ * /addons`, read off the "Subscriptions you might like" row with the shared hydration parser.
27253
+ * **Carries no price.** The two dollar strings on the whole page are a card's own compact
27254
+ * offer wording, never a clean number, so `offerMessage` carries the site's own sentence
27255
+ * instead. Most cards carry both ids; a card with no channel page of its own (CNN All Access)
27256
+ * carries only `benefitId`, and one further outlier (NBA League Pass, a subscription pass
27257
+ * rather than a channel) carries neither — both real, measured gaps, never a guess.
27258
+ */
27259
+ listChannels(): Promise<PrimeVideoChannel[]>;
27260
+
27261
+ /**
27262
+ * Read one add-on channel: what it is called, its top ten, its originals and series, and the
27263
+ * live events it is carrying — the rest of a channel's catalogue, for answering "is it worth
27264
+ * subscribing to this to watch that" rather than one title. Takes the channel's uuid off
27265
+ * listChannels(), e.g. one read off `channelId` there — NOT the same card's `benefitId`, which
27266
+ * opens a different route. `GET /channel/<uuid>`, read off the same carousel parser
27267
+ * listCategoryTitles() uses: a heading and every title under it, per row, in the site's own
27268
+ * order. `rows` never includes the channel's own hero banner, which carries no title list of
27269
+ * its own.
27270
+ */
27271
+ getChannel(channelId: string): Promise<PrimeVideoChannelDetail>;
27272
+
27273
+ /**
27274
+ * List the free live TV ("livetv", off `/livetv`) or news ("news", off `/news`) stations Prime
27275
+ * Video streams — their name, their logo, the id that addresses them, which row they are
27276
+ * grouped under (on `/livetv` the channel selling them, "Prime" or "AMC+"; on `/news` a topic
27277
+ * like "National news"), and what is on each one right now. The half of this site that has
27278
+ * nothing to do with the on-demand catalogue. `nowPlaying` is derived by walking the station's
27279
+ * own schedule for the entry covering this moment, never read off a per-entry badge — measured
27280
+ * 2026-09-16, every schedule entry on both pages carries the identical `linearBadge: {label:
27281
+ * "ON NOW"}` whether or not it is actually airing, so that field cannot say which slot is
27282
+ * current. `nowPlaying` is `null`, a real answer, when no entry covers this instant. A station
27283
+ * whose card appears on more than one row on the same page (an unheaded hero container
27284
+ * duplicating a station a headed row below it already carries) is returned once, off the
27285
+ * headed row — an unheaded container is dropped whole.
27286
+ */
27287
+ listLiveChannels(section: "livetv" | "news"): Promise<PrimeVideoLiveStation[]>;
27288
+
27289
+ /**
27290
+ * Read one live TV or news station's FULL schedule — every program the page carries for it, in
27291
+ * order, never filtered to what is on now (that single entry is `listLiveChannels()`'s own
27292
+ * `nowPlaying`). `start` and `end` are EPOCH MILLISECONDS, never the page's
27293
+ * `localizedTimeRange` ("9 - 9:30 AM EDT"), which is rendered for Amazon's assumed timezone
27294
+ * and useless to a caller in another one. Takes the SAME `section` `listLiveChannels(section)`
27295
+ * was called with and a `stationId` read off one of its rows — `/livetv` and `/news` carry
27296
+ * different stations, so a `livetv` id will not resolve on `/news`. Refuses (caller-fixable)
27297
+ * when the page carries no station with that id.
27298
+ */
27299
+ getLiveSchedule(section: "livetv" | "news", stationId: string): Promise<PrimeVideoLiveProgram[]>;
27300
+ }
27301
+ }
27302
+
24898
27303
  declare namespace BowmarkProvider_progressive {
24899
27304
  // ── Progressive — the unit's own declarations, verbatim ──
24900
27305
  // Progressive's OWN shapes — not a capability contract.
@@ -27356,6 +29761,47 @@ interface SemihandmadePriceResult {
27356
29761
  }
27357
29762
  }
27358
29763
 
29764
+ declare namespace BowmarkProvider_serper {
29765
+ // ── Serper — the unit's own declarations, verbatim ──
29766
+ interface SerperOrganicResult {
29767
+ position: number;
29768
+ title: string;
29769
+ link: string; // the destination url
29770
+ snippet: string | null;
29771
+ date: string | null;
29772
+ }
29773
+
29774
+ interface SerperSearchOptions {
29775
+ num?: number; // 1-100, default 10
29776
+ gl?: string; // country, e.g. "us"
29777
+ hl?: string; // language, e.g. "en"
29778
+ }
29779
+
29780
+ interface SerperSearchResult {
29781
+ query: string;
29782
+ results: SerperOrganicResult[]; // empty only when Google matched nothing
29783
+ credits: number | null; // Serper credits this search spent
29784
+ warnings: string[];
29785
+ }
29786
+
29787
+ /**
29788
+ * Google's own search results as JSON through Serper's API — honours site:, quoted phrases and
29789
+ * every other Google operator, in about a second. Uses Bowmark's Serper key and charges each
29790
+ * search to your account, or your own key sent as the `x-bowmark-vendor-key-serper` header.
29791
+ */
29792
+ interface Unit {
29793
+ /**
29794
+ * Runs a Google search and returns Google's organic results — position, title, destination
29795
+ * url, snippet — with every Google operator honoured. `site:cal.com "Chris Field"` returns
29796
+ * only cal.com pages naming him (cal.com/analytics/quick-chat among them), which is how to
29797
+ * find a page on one site by any words printed on it. An empty `results` is Google matching
29798
+ * nothing. Uses Bowmark's Serper key and charges each search to your account; send your own
29799
+ * key as the `x-bowmark-vendor-key-serper` header to spend your own credits instead.
29800
+ */
29801
+ searchGoogle(query: string, opts?: SerperSearchOptions): Promise<SerperSearchResult>;
29802
+ }
29803
+ }
29804
+
27359
29805
  declare namespace BowmarkProvider_sitmeanssit {
27360
29806
  // ── Sit Means Sit — the unit's own declarations, verbatim ──
27361
29807
  interface SitmeanssitLocation {
@@ -27699,6 +30145,88 @@ interface ScPlaylist {
27699
30145
  }
27700
30146
  }
27701
30147
 
30148
+ declare namespace BowmarkProvider_speedrun {
30149
+ // ── speedrun.com — the unit's own declarations, verbatim ──
30150
+ interface FindGameArgs {
30151
+ name: string;
30152
+ }
30153
+
30154
+ interface CategoriesArgs {
30155
+ gameId: string;
30156
+ }
30157
+
30158
+ interface PlatformsArgs {
30159
+ gameId?: string;
30160
+ }
30161
+
30162
+ interface Game {
30163
+ id: string;
30164
+ names: { international: string; japanese?: string };
30165
+ abbreviation: string;
30166
+ weblink: string;
30167
+ released: number;
30168
+ "release-date": string;
30169
+ platforms?: string[];
30170
+ ruleset?: { "require-video": boolean; "require-verification": boolean; "show-milliseconds": boolean };
30171
+ }
30172
+
30173
+ interface Category {
30174
+ id: string;
30175
+ name: string;
30176
+ weblink: string;
30177
+ type: string; // "per-game" | "per-level"
30178
+ rules?: string;
30179
+ players?: { type: string; value?: number }
30180
+ miscellaneous?: boolean; // hidden from the default leaderboard view
30181
+ variables?: { data: CategoryVariable[] }
30182
+ }
30183
+
30184
+ interface CategoryVariable {
30185
+ id: string;
30186
+ name: string;
30187
+ mandatory: boolean;
30188
+ "user-defined": boolean;
30189
+ // submitRun takes the KEY of a choice, never its label
30190
+ values?: { choices?: Record<string, { label: string }>; default?: string }
30191
+ }
30192
+
30193
+ interface Platform {
30194
+ id: string;
30195
+ name: string;
30196
+ released?: number;
30197
+ }
30198
+
30199
+ /** Submit speedruns and search game metadata on speedrun.com */
30200
+ interface Unit {
30201
+ /**
30202
+ * Searches games by name and returns the matches with the metadata every other call here needs
30203
+ * — the opaque `id`, the abbreviation, the weblink, the platform ids, and the `ruleset` that
30204
+ * says whether a video is required and whether milliseconds are shown. Start here:
30205
+ * speedrun.com addresses everything by id and nothing by title. The search is fuzzy and
30206
+ * ranked, so read the first row rather than assuming one match, and an unknown title returns
30207
+ * an empty array rather than an error.
30208
+ */
30209
+ findGame(args: FindGameArgs): Promise<Game[]>;
30210
+
30211
+ /**
30212
+ * Lists every category for one game, with the variables each one carries. The `variables`
30213
+ * block is the part that matters before a submit: a category with a `mandatory` variable
30214
+ * rejects a run that omits it, and the accepted values are the keys of `values.choices`, not
30215
+ * their labels. `type` separates a per-game category from a per-level one, and
30216
+ * `is-miscellaneous` marks the ones the leaderboard hides by default.
30217
+ */
30218
+ categories(args: CategoriesArgs): Promise<Category[]>;
30219
+
30220
+ /**
30221
+ * Lists platforms as `{ id, name, released }` — called with no argument it returns the whole
30222
+ * speedrun.com platform table, and with a `gameId` only the platforms that game accepts.
30223
+ * Prefer the `gameId` form when you need the platform a specific game accepts — the whole
30224
+ * table is ~140 rows and most of them are not playable for any one game.
30225
+ */
30226
+ platforms(args?: PlatformsArgs): Promise<Platform[]>;
30227
+ }
30228
+ }
30229
+
27702
30230
  declare namespace BowmarkProvider_spirithalloween {
27703
30231
  // ── Spirit Halloween — the unit's own declarations, verbatim ──
27704
30232
  interface SpiritHalloweenSearchResult {
@@ -30152,6 +32680,99 @@ type TwiddyQuote =
30152
32680
  }
30153
32681
  }
30154
32682
 
32683
+ declare namespace BowmarkProvider_twitch {
32684
+ // ── Twitch — the unit's own declarations, verbatim ──
32685
+ interface TwitchVideo {
32686
+ id: string;
32687
+ title: string;
32688
+ /** Seconds. For a live archive this GROWS, trailing real time by a minute or two. */
32689
+ lengthSeconds: number;
32690
+ /** "RECORDING" while the broadcast is live, "RECORDED" after. */
32691
+ status: string;
32692
+ /** "ARCHIVE" (a past broadcast), "HIGHLIGHT" or "UPLOAD". */
32693
+ type: string;
32694
+ createdAt: string;
32695
+ ownerLogin: string;
32696
+ url: string;
32697
+ }
32698
+ interface GetVideoArgs {
32699
+ /** A Twitch video id, or a twitch.tv/videos/<id> link. */
32700
+ vodId: string;
32701
+ }
32702
+ interface CreateHighlightArgs {
32703
+ /** The broadcast to cut from — an id or a twitch.tv/videos/<id> link. Omit it
32704
+ * for the signed-in channel's NEWEST archive, which during a broadcast is the
32705
+ * live one. */
32706
+ vodId?: string;
32707
+ /** Seconds into that video. Rounded outward to whole seconds. */
32708
+ startSeconds: number;
32709
+ endSeconds: number;
32710
+ title: string;
32711
+ description?: string;
32712
+ /** Default "en". */
32713
+ language?: string;
32714
+ tags?: string[];
32715
+ /** Category name, e.g. "Wetrix". */
32716
+ game?: string;
32717
+ }
32718
+ interface TwitchHighlight {
32719
+ /** "created" by this call; "existing" when a highlight with this exact title
32720
+ * was already on the channel (nothing new made); "unknown" when the request
32721
+ * went out and no answer came back — check dashboardUrl before retrying. */
32722
+ status: "created" | "existing" | "unknown";
32723
+ highlightId: string | null;
32724
+ url: string | null;
32725
+ title: string;
32726
+ vodId: string;
32727
+ startSeconds: number;
32728
+ endSeconds: number;
32729
+ channel: string;
32730
+ dashboardUrl: string;
32731
+ }
32732
+ interface RegisterDeveloperAppArgs {
32733
+ /** Application name */
32734
+ name: string;
32735
+ /** OAuth redirect URI(s), comma-separated if multiple */
32736
+ redirectUri: string;
32737
+ /** "Application Integration" or "Website Integration" */
32738
+ category: string;
32739
+ /** "Public" or "Confidential" */
32740
+ clientType?: string;
32741
+ }
32742
+ interface TwitchDeveloperApp {
32743
+ clientId: string;
32744
+ clientSecret?: string;
32745
+ name: string;
32746
+ redirectUri: string;
32747
+ dashboardUrl: string;
32748
+ }
32749
+
32750
+ /**
32751
+ * Twitch — cut a Highlight of your own broadcast, including the one still live, and read any
32752
+ * public video's length and status.
32753
+ */
32754
+ interface Unit {
32755
+ /**
32756
+ * Reads one public Twitch video by id or twitch.tv/videos link — title, length in seconds,
32757
+ * whether it is still RECORDING (a live broadcast's archive) or RECORDED, its type (ARCHIVE,
32758
+ * HIGHLIGHT, UPLOAD) and its channel. No sign-in. THROWS naming the id when Twitch has no such
32759
+ * video.
32760
+ */
32761
+ getVideo(args: GetVideoArgs): Promise<TwitchVideo>;
32762
+
32763
+ /**
32764
+ * Cuts a permanent Highlight from the signed-in streamer's own broadcast — including the one
32765
+ * still live — between two offsets in seconds, with a title. Omit vodId to cut from the newest
32766
+ * archive. NEEDS the streamer's Twitch sign-in, which only a capability can hold: call it as
32767
+ * bowmark.stream_highlights.create. Idempotent on the title: a highlight whose title already
32768
+ * exists on the channel is returned with status "existing" rather than made twice. Refuses,
32769
+ * without asking for a sign-in, a vod id Twitch does not have or an end offset past what the
32770
+ * live archive has recorded so far (retry shortly in that case).
32771
+ */
32772
+ createHighlight(args: CreateHighlightArgs): Promise<TwitchHighlight>;
32773
+ }
32774
+ }
32775
+
30155
32776
  declare namespace BowmarkProvider_uhc_smallbusiness {
30156
32777
  // ── UnitedHealthcare Small Business — the unit's own declarations, verbatim ──
30157
32778
  interface UhcSmallbusinessPlan {
@@ -32576,6 +35197,7 @@ interface BowmarkProviders {
32576
35197
  ajmadison: BowmarkProvider_ajmadison.Unit;
32577
35198
  allied: BowmarkProvider_allied.Unit;
32578
35199
  alphavantage: BowmarkProvider_alphavantage.Unit;
35200
+ amazon: BowmarkProvider_amazon.Unit;
32579
35201
  americandreamvacations: BowmarkProvider_americandreamvacations.Unit;
32580
35202
  americanstandard: BowmarkProvider_americanstandard.Unit;
32581
35203
  americanvisionwindows: BowmarkProvider_americanvisionwindows.Unit;
@@ -32586,6 +35208,7 @@ interface BowmarkProviders {
32586
35208
  anthropic_com: BowmarkProvider_anthropic_com.Unit;
32587
35209
  antunes: BowmarkProvider_antunes.Unit;
32588
35210
  aosom: BowmarkProvider_aosom.Unit;
35211
+ app_store: BowmarkProvider_app_store.Unit;
32589
35212
  apple: BowmarkProvider_apple.Unit;
32590
35213
  aquaphoenixsci: BowmarkProvider_aquaphoenixsci.Unit;
32591
35214
  arajet: BowmarkProvider_arajet.Unit;
@@ -32690,6 +35313,7 @@ interface BowmarkProviders {
32690
35313
  cruiselakegeneva: BowmarkProvider_cruiselakegeneva.Unit;
32691
35314
  culturefly: BowmarkProvider_culturefly.Unit;
32692
35315
  curiocity: BowmarkProvider_curiocity.Unit;
35316
+ currency_exchange: BowmarkProvider_currency_exchange.Unit;
32693
35317
  cyberpowerpc: BowmarkProvider_cyberpowerpc.Unit;
32694
35318
  dahlconsulting: BowmarkProvider_dahlconsulting.Unit;
32695
35319
  dansons: BowmarkProvider_dansons.Unit;
@@ -32697,6 +35321,7 @@ interface BowmarkProviders {
32697
35321
  deangroup: BowmarkProvider_deangroup.Unit;
32698
35322
  decked: BowmarkProvider_decked.Unit;
32699
35323
  decksdirect: BowmarkProvider_decksdirect.Unit;
35324
+ dell: BowmarkProvider_dell.Unit;
32700
35325
  deltadentalma: BowmarkProvider_deltadentalma.Unit;
32701
35326
  dentalplans: BowmarkProvider_dentalplans.Unit;
32702
35327
  detailxperts: BowmarkProvider_detailxperts.Unit;
@@ -32754,6 +35379,9 @@ interface BowmarkProviders {
32754
35379
  goloadup: BowmarkProvider_goloadup.Unit;
32755
35380
  goodway: BowmarkProvider_goodway.Unit;
32756
35381
  google_flights: BowmarkProvider_google_flights.Unit;
35382
+ google_maps: BowmarkProvider_google_maps.Unit;
35383
+ google_news: BowmarkProvider_google_news.Unit;
35384
+ google_translate: BowmarkProvider_google_translate.Unit;
32757
35385
  gostoreit: BowmarkProvider_gostoreit.Unit;
32758
35386
  gotchacovered: BowmarkProvider_gotchacovered.Unit;
32759
35387
  grainger: BowmarkProvider_grainger.Unit;
@@ -32767,6 +35395,7 @@ interface BowmarkProviders {
32767
35395
  hauslabs: BowmarkProvider_hauslabs.Unit;
32768
35396
  havenenergy: BowmarkProvider_havenenergy.Unit;
32769
35397
  haydenhomes: BowmarkProvider_haydenhomes.Unit;
35398
+ hccts: BowmarkProvider_hccts.Unit;
32770
35399
  healthcare_gov: BowmarkProvider_healthcare_gov.Unit;
32771
35400
  heatherwood: BowmarkProvider_heatherwood.Unit;
32772
35401
  hellofresh: BowmarkProvider_hellofresh.Unit;
@@ -32875,6 +35504,7 @@ interface BowmarkProviders {
32875
35504
  positivegrid: BowmarkProvider_positivegrid.Unit;
32876
35505
  postiz: BowmarkProvider_postiz.Unit;
32877
35506
  premierbuildings: BowmarkProvider_premierbuildings.Unit;
35507
+ prime_video: BowmarkProvider_prime_video.Unit;
32878
35508
  progressive: BowmarkProvider_progressive.Unit;
32879
35509
  prolook: BowmarkProvider_prolook.Unit;
32880
35510
  prose: BowmarkProvider_prose.Unit;
@@ -32903,6 +35533,7 @@ interface BowmarkProviders {
32903
35533
  selectblinds: BowmarkProvider_selectblinds.Unit;
32904
35534
  sellcell: BowmarkProvider_sellcell.Unit;
32905
35535
  semihandmade: BowmarkProvider_semihandmade.Unit;
35536
+ serper: BowmarkProvider_serper.Unit;
32906
35537
  sitmeanssit: BowmarkProvider_sitmeanssit.Unit;
32907
35538
  sixflags: BowmarkProvider_sixflags.Unit;
32908
35539
  smartsign: BowmarkProvider_smartsign.Unit;
@@ -32910,6 +35541,7 @@ interface BowmarkProviders {
32910
35541
  smithery: BowmarkProvider_smithery.Unit;
32911
35542
  solostove: BowmarkProvider_solostove.Unit;
32912
35543
  soundcloud: BowmarkProvider_soundcloud.Unit;
35544
+ speedrun: BowmarkProvider_speedrun.Unit;
32913
35545
  spirithalloween: BowmarkProvider_spirithalloween.Unit;
32914
35546
  starlighthomes: BowmarkProvider_starlighthomes.Unit;
32915
35547
  statefarm: BowmarkProvider_statefarm.Unit;
@@ -32941,6 +35573,7 @@ interface BowmarkProviders {
32941
35573
  tryalma_com: BowmarkProvider_tryalma_com.Unit;
32942
35574
  tweethunter: BowmarkProvider_tweethunter.Unit;
32943
35575
  twiddy: BowmarkProvider_twiddy.Unit;
35576
+ twitch: BowmarkProvider_twitch.Unit;
32944
35577
  uhc_smallbusiness: BowmarkProvider_uhc_smallbusiness.Unit;
32945
35578
  ulrichlifestyle: BowmarkProvider_ulrichlifestyle.Unit;
32946
35579
  upkeepstl_com: BowmarkProvider_upkeepstl_com.Unit;
@@ -84690,11 +87323,13 @@ interface BowmarkProviders {
84690
87323
  * `run()` script, and the Proxy over HTTP in a caller's own process. They are
84691
87324
  * generated once precisely so those two cannot drift. */
84692
87325
  interface BowmarkLibrary {
87326
+ booking_links: BowmarkCapability_booking_links.Unit;
84693
87327
  bundles: BowmarkCapability_bundles.Unit;
84694
87328
  cable_railing_quote: BowmarkCapability_cable_railing_quote.Unit;
84695
87329
  cars: BowmarkCapability_cars.Unit;
84696
87330
  costume_size_check: BowmarkCapability_costume_size_check.Unit;
84697
87331
  coworking: BowmarkCapability_coworking.Unit;
87332
+ currency_exchange: BowmarkCapability_currency_exchange.Unit;
84698
87333
  custom_sofa_configurator: BowmarkCapability_custom_sofa_configurator.Unit;
84699
87334
  delivery: BowmarkCapability_delivery.Unit;
84700
87335
  developer_api_key_signup: BowmarkCapability_developer_api_key_signup.Unit;
@@ -84729,6 +87364,7 @@ interface BowmarkLibrary {
84729
87364
  search: BowmarkCapability_search.Unit;
84730
87365
  sheds: BowmarkCapability_sheds.Unit;
84731
87366
  shipping: BowmarkCapability_shipping.Unit;
87367
+ stream_highlights: BowmarkCapability_stream_highlights.Unit;
84732
87368
  tariff: BowmarkCapability_tariff.Unit;
84733
87369
  text_to_speech: BowmarkCapability_text_to_speech.Unit;
84734
87370
  theme_park_tickets: BowmarkCapability_theme_park_tickets.Unit;