@bowmark/web 1.24.1 → 1.24.2

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: 83b6073de78d83a7366cd17844242d5703320faa6ea88973baea85a98639f7d0
9
- // 51 capabilities, 419 providers, 1122 typed functions, 20 refused.
8
+ // Manifest version: 8cc406ad353aaf7223bd7938597d0198b89ecc312e3388dff6a1c405b92c38a8
9
+ // 56 capabilities, 434 providers, 1182 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
@@ -217,18 +217,34 @@ type CallOptions = {
217
217
 
218
218
  /**
219
219
  * LAST RESORT, and it costs money: hands a plain-language task to a hosted AI browser agent
220
- * (Browser Use) when no Bowmark function covers the site or a script against one failed.
221
- * Returns a session id and a private link your user can open to watch and take over the live
222
- * browser; later scripts poll it, answer its questions and stop it.
220
+ * (Browser Use) when no Bowmark function covers the site or a script against one failed. When
221
+ * it is the only path left, USE it rather than silently declining or only describing it: call
222
+ * `start`, and in the same reply tell your user it is starting, that it is billed, and give
223
+ * them the real watchUrl it returns so they can watch and take over (log in, solve a captcha).
224
+ * A site gated on a login only your user holds is exactly this case, not a reason to stop
225
+ * short of calling `start` — the watchUrl is how they supply the credential, not something you
226
+ * need in hand first. Never start a session without your user knowing it happened. **CRITICAL:
227
+ * one task = one independent goal. Bundle multiple date ranges, product SKUs, or queries into
228
+ * one task and the agent may silently reuse a single search result across all of them with no
229
+ * warning. For each distinct item, start a separate session.** RUN-ONLY: a typed session
230
+ * cannot call it (that is refused with code "run_only", and it is never an API-key problem),
231
+ * and one run is killed at 120s of wall clock — so `start` in one run and poll `status` from
232
+ * LATER runs, never in a loop inside one.
223
233
  */
224
234
  interface Unit {
225
235
  /**
226
236
  * Starts a hosted browser agent on `task` and returns at once with its session `id` and a
227
- * `watchUrl`. Use ONLY after the library had nothing for this site or a function failed — each
228
- * turn spends real vendor money, charged to the account. Your account may hold up to 3
229
- * concurrent sessions; call `list()` before starting if looping over multiple tasks. Show
230
- * `watchUrl` to your user: it lets them watch the agent and take over the browser (log in,
231
- * solve a captcha). Then poll with `status`. Always `stop()` a session when done.
237
+ * `watchUrl`. **CRITICAL: one task = one independent goal.** If you need prices for 5 date
238
+ * ranges, 5 SKUs, or 5 queries, start 5 separate sessions bundling them into one task causes
239
+ * the agent to silently reuse results across different items with no warning. Use ONLY after
240
+ * the library had nothing for this site or a function failed each turn spends real vendor
241
+ * money, charged to the account. Call it, don't just describe it: tell your user you're doing
242
+ * this and why, in the same reply as calling it — don't wait for permission first just because
243
+ * it's billed, and don't decide silently on their behalf either. A login only your user holds
244
+ * is what `watchUrl` is for, not a reason to stop before calling `start`. Your account may
245
+ * hold up to 3 concurrent sessions; call `list()` before starting if looping over multiple
246
+ * tasks. Show `watchUrl` to your user: it lets them watch the agent and take over the browser
247
+ * (log in, solve a captcha). Then poll with `status`. Always `stop()` a session when done.
232
248
  */
233
249
  start(options: StartBrowserAgentOptions): Promise<StartBrowserAgentResult>;
234
250
 
@@ -544,6 +560,34 @@ type CallOptions = {
544
560
  }
545
561
  }
546
562
 
563
+ declare namespace BowmarkCapability_custom_packaging_quote {
564
+ // ── Custom Packaging Quote — the unit's own declarations, verbatim ──
565
+ interface CustomPackagingQuote {
566
+ price: { amount: number; currency: string };
567
+ unitPrice: { amount: number; currency: string };
568
+ }
569
+
570
+ interface custom_packaging_quoteResult {
571
+ quotes: CustomPackagingQuote[];
572
+ warnings: string[];
573
+ }
574
+
575
+ type CallOptions = {
576
+ timeoutMs?: number // per-provider budget in ms, default 30000, clamped to 1000-55000.
577
+ // A provider slower than this is DROPPED from the results and
578
+ // NAMED in warnings — never silently absent
579
+ }
580
+
581
+ /**
582
+ * Quotes custom printed packaging boxes — shipping boxes, mailer boxes — with real,
583
+ * quantity-tiered pricing from live configurators.
584
+ */
585
+ interface Unit {
586
+ /** Gets a real, quantity-tiered price for a custom printed box from available suppliers. */
587
+ quoteCustomBox(args: { size: string; printArea: string; quantity: number }): Promise<custom_packaging_quoteResult>;
588
+ }
589
+ }
590
+
547
591
  declare namespace BowmarkCapability_custom_sofa_configurator {
548
592
  // ── Custom sofa configurator (fabric selection, live pricing) — the unit's own declarations, verbatim ──
549
593
  type CustomSofa = {
@@ -704,6 +748,35 @@ type CallOptions = {
704
748
  }
705
749
  }
706
750
 
751
+ declare namespace BowmarkCapability_dfs_ownership_projections {
752
+ // ── DFS Ownership & Salary Projections — the unit's own declarations, verbatim ──
753
+ interface DFSProjection {
754
+ player: string;
755
+ salary: number;
756
+ ownership: number;
757
+ sport?: string;
758
+ position?: string;
759
+ team?: string;
760
+ }
761
+
762
+ interface dfs_ownership_projectionsResult {
763
+ projections: DFSProjection[];
764
+ warnings: string[];
765
+ }
766
+
767
+ type CallOptions = {
768
+ timeoutMs?: number // per-provider budget in ms, default 30000, clamped to 1000-55000.
769
+ // A provider slower than this is DROPPED from the results and
770
+ // NAMED in warnings — never silently absent
771
+ }
772
+
773
+ /** Projected ownership percentages and salary caps for daily fantasy sports slates */
774
+ interface Unit {
775
+ /** Search for DFS ownership percentages and salary data across sports and slates */
776
+ search(query: string, options?: CallOptions): Promise<dfs_ownership_projectionsResult>;
777
+ }
778
+ }
779
+
707
780
  declare namespace BowmarkCapability_domain {
708
781
  // ── Domain name availability check — the unit's own declarations, verbatim ──
709
782
 
@@ -1732,6 +1805,25 @@ interface HtmlPreviewResult {
1732
1805
  }
1733
1806
  }
1734
1807
 
1808
+ declare namespace BowmarkCapability_mac_trade_in {
1809
+ // ── Mac trade-in value — the unit's own declarations, verbatim ──
1810
+ interface MacTradeInEstimate {
1811
+ model: string;
1812
+ chip?: string;
1813
+ storage?: string;
1814
+ ram?: string;
1815
+ condition?: "like_new" | "good" | "fair" | "broken";
1816
+ appleTradeInValue: number | null;
1817
+ warnings: string[];
1818
+ }
1819
+
1820
+ /** Get Mac trade-in credit estimates from Apple Trade In. */
1821
+ interface Unit {
1822
+ /** Get the Apple Trade In credit value for a Mac model, with optional specs. */
1823
+ estimate(model: string, options?: { chip?: string; storage?: string; ram?: string; condition?: string }): Promise<MacTradeInEstimate>;
1824
+ }
1825
+ }
1826
+
1735
1827
  declare namespace BowmarkCapability_mcp_registry {
1736
1828
  // ── MCP Registry — the unit's own declarations, verbatim ──
1737
1829
  interface McpRegistryEntry {
@@ -2076,6 +2168,40 @@ type CallOptions = {
2076
2168
  }
2077
2169
  }
2078
2170
 
2171
+ declare namespace BowmarkCapability_postcard_direct_mail_quote {
2172
+ // ── Direct mail postcard printing quote — the unit's own declarations, verbatim ──
2173
+ interface GetQuoteArgs {
2174
+ quantity: number
2175
+ size?: string
2176
+ stock?: string
2177
+ }
2178
+
2179
+ interface PostcardQuoteLineItem {
2180
+ size: string
2181
+ stock: string
2182
+ totalPrice: number
2183
+ unitPrice: number
2184
+ currency: string
2185
+ }
2186
+
2187
+ interface PostcardDirectMailQuote {
2188
+ quantity: number
2189
+ lineItems: PostcardQuoteLineItem[]
2190
+ estimatedDeliveryDays?: number
2191
+ checkoutUrl?: string
2192
+ warnings: string[]
2193
+ }
2194
+
2195
+ /** Get a quote for printing direct mail postcards — pricing by quantity, size, and stock. */
2196
+ interface Unit {
2197
+ /**
2198
+ * Returns pricing for direct mail postcards at a requested quantity, with optional size and
2199
+ * stock specifications.
2200
+ */
2201
+ getQuote(args: { quantity: number; size?: string; stock?: string }): Promise<PostcardDirectMailQuote>;
2202
+ }
2203
+ }
2204
+
2079
2205
  declare namespace BowmarkCapability_pricing {
2080
2206
  // ── Check whether a product page quotes a different price to different shoppers — the unit's own declarations, verbatim ──
2081
2207
  interface PersonalizationPersona {
@@ -2284,14 +2410,21 @@ type ReadResult = {
2284
2410
  * Loads one page and returns its content. Tries a plain GET first and escalates to a real
2285
2411
  * browser only when the response proves it needs one (a bot wall, an interstitial, or markup
2286
2412
  * carrying no words) — `servedBy` says which leg paid for it. Reports a failure IN the result
2287
- * rather than throwing.
2413
+ * rather than throwing. RUN-ONLY: because the rung is decided per call, neither `session()`
2414
+ * nor the bare top-level `bowmark` client (which opens a session internally, even for one
2415
+ * call) can serve this — both are refused with code "rung_undeclared". Call it through `run()`
2416
+ * instead.
2288
2417
  */
2289
2418
  page(url: string, options?: ReadOptions): Promise<ReadResult>;
2290
2419
 
2291
2420
  /**
2292
- * The same read over many urls, six in flight at a time, results in the order the urls were
2421
+ * The same read over many urls: requests to the SAME origin are serialized (one at a time) to
2422
+ * avoid triggering bot defenses on sites that block concurrent connections from one IP, while
2423
+ * requests to DIFFERENT origins run in parallel. Results arrive in the order the urls were
2293
2424
  * given. One dead url never costs you the others — it comes back with `ok: false` and `error`
2294
- * set.
2425
+ * set. RUN-ONLY: same reason as `page` — the rung is decided per call, so `session()` and the
2426
+ * top-level `bowmark` client are both refused with code "rung_undeclared". Call it through
2427
+ * `run()` instead.
2295
2428
  */
2296
2429
  pages(urls: string[], options?: ReadOptions): Promise<ReadResult[]>;
2297
2430
  }
@@ -3015,6 +3148,118 @@ type CallOptions = {
3015
3148
  }
3016
3149
  }
3017
3150
 
3151
+ declare namespace BowmarkCapability_video_library {
3152
+ // ── Video library — the caller's own saved, liked and playlisted videos — the unit's own declarations, verbatim ──
3153
+ interface LibraryVideo {
3154
+ videoId: string
3155
+ url: string
3156
+ title: string
3157
+ channel: string | null
3158
+ views: string | null // the site's own text, e.g. "1.2M views" — never a parsed number
3159
+ length: string | null // e.g. "22:28"; null for a live stream
3160
+ }
3161
+ interface LibraryPage {
3162
+ videos: LibraryVideo[]
3163
+ continuation: string | null // pass back for the next page; null on the last
3164
+ warnings: string[]
3165
+ }
3166
+ interface CreatePlaylistOptions {
3167
+ title: string
3168
+ description?: string
3169
+ privacy?: "private" | "unlisted" | "public" // default "private"
3170
+ // "unlisted" and "public" need the signed-in account to HAVE a YouTube channel;
3171
+ // "private" does not. Without one the call fails and says so.
3172
+ }
3173
+ interface CreatedChannel {
3174
+ channelId: string
3175
+ name: string // the account's own Google profile name
3176
+ url: string
3177
+ alreadyExisted: boolean // true when it already had one; nothing was created
3178
+ warnings: string[]
3179
+ }
3180
+ interface CreatedPlaylist {
3181
+ playlistId: string
3182
+ title: string
3183
+ privacy: "private" | "unlisted" | "public"
3184
+ url: string // show this to your user — it opens the playlist
3185
+ warnings: string[]
3186
+ }
3187
+ interface AddToPlaylistOptions {
3188
+ playlist: string // a playlist id, or any URL carrying a "list" param
3189
+ video?: string // one video id or watch URL
3190
+ videos?: string[] // or several — sent as ONE edit
3191
+ }
3192
+ interface PlaylistEdit {
3193
+ playlistId: string
3194
+ added: string[] // what was sent and accepted, in order — not a per-video receipt
3195
+ url: string
3196
+ warnings: string[]
3197
+ }
3198
+
3199
+ type CallOptions = {
3200
+ timeoutMs?: number // per-provider budget in ms, default 30000, clamped to 1000-55000.
3201
+ // A provider slower than this is DROPPED from the results and
3202
+ // NAMED in warnings — never silently absent
3203
+ }
3204
+
3205
+ /**
3206
+ * Reads and writes the caller's OWN YouTube account: their Watch Later list, their liked
3207
+ * videos, and the playlists they keep — including making a new one and adding videos to it.
3208
+ * Needs the caller's YouTube sign-in: the first run answers needs_user with a link to sign in,
3209
+ * and later runs reuse it with no browser.
3210
+ */
3211
+ interface Unit {
3212
+ /**
3213
+ * The videos on the caller's OWN YouTube home page — the personalized recommendation grid, in
3214
+ * YouTube's own order, which is what they see when they open youtube.com right now. It exists
3215
+ * nowhere else: not in YouTube's public API, and logged out the same request answers an EMPTY
3216
+ * grid rather than an error. `continuation` is always null; the home feed is one ranked page.
3217
+ * Needs a YouTube sign-in.
3218
+ */
3219
+ homeFeed(options?: { limit?: number }): Promise<LibraryPage>;
3220
+
3221
+ /**
3222
+ * The caller's own Watch Later queue, newest first. Not reachable through YouTube's public API
3223
+ * at all — Google removed access to this list in 2016. Needs a YouTube sign-in.
3224
+ */
3225
+ watchLater(options?: { continuation?: string }): Promise<LibraryPage>;
3226
+
3227
+ /** The videos the caller has liked, newest first. Needs a YouTube sign-in. */
3228
+ liked(options?: { continuation?: string }): Promise<LibraryPage>;
3229
+
3230
+ /**
3231
+ * Creates an empty playlist on the caller's own account and returns its id and URL. Defaults
3232
+ * to "private". A "public" or "unlisted" playlist also needs the account to have a YouTube
3233
+ * channel — a private one does not — and the call says so when it is missing; `createChannel`
3234
+ * makes one, with the account holder's say-so. NOT idempotent — calling it twice makes two
3235
+ * playlists, because YouTube allows duplicate titles and picking one for you would be a guess.
3236
+ * TITLE IT FOR THE PERSON WHOSE ACCOUNT IT LANDS ON — the subject in their own words, never a
3237
+ * tool name, run id or timestamp — and fill in `description` saying what the videos have in
3238
+ * common; see `CreatePlaylistOptions`. Needs a YouTube sign-in.
3239
+ */
3240
+ createPlaylist(options: CreatePlaylistOptions): Promise<CreatedPlaylist>;
3241
+
3242
+ /**
3243
+ * Gives the signed-in account a YouTube CHANNEL, under its own Google profile name and photo —
3244
+ * there is nothing to fill in, because YouTube's own dialog offers nothing. Most Google
3245
+ * accounts have never had one, and without one YouTube REFUSES to create a public or unlisted
3246
+ * playlist (a private one still works, because that belongs to the account rather than to a
3247
+ * channel). THIS ACCEPTS YOUTUBE'S TERMS OF SERVICE for the account holder, exactly as their
3248
+ * own Create channel button does — so call it when the person whose account it is has asked
3249
+ * for a channel, and never on your own to clear an error. Safe to call twice: an account that
3250
+ * already has one gets `alreadyExisted: true` and nothing is created. Needs a YouTube sign-in.
3251
+ */
3252
+ createChannel(): Promise<CreatedChannel>;
3253
+
3254
+ /**
3255
+ * Adds one or many videos to one of the caller's own playlists, as a single edit. Adding a
3256
+ * video already in the playlist adds it again — YouTube permits duplicates and does not report
3257
+ * which is which. Needs a YouTube sign-in.
3258
+ */
3259
+ addToPlaylist(options: AddToPlaylistOptions): Promise<PlaylistEdit>;
3260
+ }
3261
+ }
3262
+
3018
3263
  declare namespace BowmarkCapability_weather {
3019
3264
  // ── Weather forecast for a place — the unit's own declarations, verbatim ──
3020
3265
 
@@ -3995,6 +4240,78 @@ interface AiperPoolRecommendation {
3995
4240
  }
3996
4241
  }
3997
4242
 
4243
+ declare namespace BowmarkProvider_airtable {
4244
+ // ── Airtable — the unit's own declarations, verbatim ──
4245
+ interface AirtableBase {
4246
+ id: string;
4247
+ name: string;
4248
+ permissionLevel: string;
4249
+ }
4250
+
4251
+ interface AirtableTable {
4252
+ id: string;
4253
+ name: string;
4254
+ primaryFieldId: string;
4255
+ fields: Array<{ id: string; name: string; type: string }>;
4256
+ }
4257
+
4258
+ interface AirtableRecord {
4259
+ id: string;
4260
+ createdTime: string;
4261
+ fields: Record<string, unknown>;
4262
+ }
4263
+
4264
+ interface ListTablesArgs {
4265
+ baseId: string;
4266
+ }
4267
+
4268
+ interface ListRecordsArgs {
4269
+ baseId: string;
4270
+ tableId: string;
4271
+ pageSize?: number;
4272
+ }
4273
+
4274
+ interface GetRecordArgs {
4275
+ baseId: string;
4276
+ tableId: string;
4277
+ recordId: string;
4278
+ }
4279
+
4280
+ interface CreateRecordArgs {
4281
+ baseId: string;
4282
+ tableId: string;
4283
+ fields: Record<string, unknown>;
4284
+ }
4285
+
4286
+ interface UpdateRecordArgs {
4287
+ baseId: string;
4288
+ tableId: string;
4289
+ recordId: string;
4290
+ fields: Record<string, unknown>;
4291
+ }
4292
+
4293
+ /** Access Airtable bases, tables, and records via the REST API. */
4294
+ interface Unit {
4295
+ /** Lists all bases the authenticated user can access. */
4296
+ listBases(): Promise<AirtableBase[]>;
4297
+
4298
+ /** Lists all tables in a specified base. */
4299
+ listTables(baseId: ListTablesArgs): Promise<AirtableTable[]>;
4300
+
4301
+ /** Lists all records in a specified table with optional filtering and sorting. */
4302
+ listRecords(args: ListRecordsArgs): Promise<AirtableRecord[]>;
4303
+
4304
+ /** Retrieves a single record by its ID from a specified table. */
4305
+ getRecord(args: GetRecordArgs): Promise<AirtableRecord>;
4306
+
4307
+ /** Creates a new record in a specified table. */
4308
+ createRecord(args: CreateRecordArgs): Promise<AirtableRecord>;
4309
+
4310
+ /** Updates an existing record by its ID. */
4311
+ updateRecord(args: UpdateRecordArgs): Promise<AirtableRecord>;
4312
+ }
4313
+ }
4314
+
3998
4315
  declare namespace BowmarkProvider_ajmadison {
3999
4316
  // ── AJ Madison — the unit's own declarations, verbatim ──
4000
4317
  interface AjmadisonSearchArgs {
@@ -4111,6 +4428,10 @@ interface AmazonProduct {
4111
4428
  ratingCount: number | null;
4112
4429
  sponsored: boolean;
4113
4430
  }
4431
+ interface AmazonSearchResult {
4432
+ products: AmazonProduct[];
4433
+ totalResultCount: number;
4434
+ }
4114
4435
  interface SearchProductsArgs {
4115
4436
  keywords: string;
4116
4437
  department?: string;
@@ -4118,6 +4439,16 @@ interface SearchProductsArgs {
4118
4439
  priceMin?: number;
4119
4440
  priceMax?: number;
4120
4441
  brand?: string;
4442
+ page?: number;
4443
+ }
4444
+ interface ListCategoryProductsArgs {
4445
+ department: string;
4446
+ sort?: string;
4447
+ page?: number;
4448
+ }
4449
+ interface AmazonCategoryListing {
4450
+ department: string;
4451
+ products: AmazonProduct[];
4121
4452
  }
4122
4453
  interface AmazonKeywordSuggestion {
4123
4454
  value: string;
@@ -4257,11 +4588,23 @@ interface AmazonSellerOffersResult {
4257
4588
  /**
4258
4589
  * Search Amazon's catalogue for what a person would type — "cast iron skillet", "usb c hub" —
4259
4590
  * and get back the result cards as the site ranks them: ASIN, title, price, list price, star
4260
- * rating, review count, whether the row is a paid placement, and its product URL. Optionally
4261
- * narrowed to a department, a brand, a price range and a sort order. THE provider's door:
4262
- * every function below that takes an ASIN is fed by this one.
4591
+ * rating, review count, whether the row is a paid placement, and its product URL, beside the
4592
+ * site's own totalResultCount so a caller paging with `page` can tell "this is the last page"
4593
+ * from "the site is walled". Optionally narrowed to a department, a brand, a price range, a
4594
+ * sort order and a page (1-based; page 2 is a genuinely different set of rows, not page one
4595
+ * repeated). THE provider's door: every function below that takes an ASIN is fed by this one.
4596
+ */
4597
+ searchProducts(args: SearchProductsArgs): Promise<AmazonSearchResult>;
4598
+
4599
+ /**
4600
+ * Browse a whole department with no keyword at all — "what is in Home & Kitchen, best-reviewed
4601
+ * first" — and page through it, sorted the way searchProducts sorts. Returns the department
4602
+ * Amazon actually searched (never the caller's slug echoed back — a department slug can
4603
+ * resolve to a DIFFERENT department than the same word means to listBestSellers) beside the
4604
+ * product rows. The function a caller reaches for when it has a category rather than a product
4605
+ * in mind.
4263
4606
  */
4264
- searchProducts(args: SearchProductsArgs): Promise<AmazonProduct[]>;
4607
+ listCategoryProducts(args: ListCategoryProductsArgs): Promise<AmazonCategoryListing>;
4265
4608
 
4266
4609
  /**
4267
4610
  * Ask Amazon's own search box what it would autocomplete a prefix to — "cast iron" comes back
@@ -5403,6 +5746,23 @@ interface AppleStore {
5403
5746
  longitude: number | null;
5404
5747
  hours: AppleStoreHours[];
5405
5748
  }
5749
+ interface AppleTodaySession {
5750
+ sessionId: string;
5751
+ title: string;
5752
+ prefix: string;
5753
+ description: string;
5754
+ startTime: string;
5755
+ endTime: string;
5756
+ timeZone: string;
5757
+ status: string; // the site's own labels — read the values off a result, never guess one from prose
5758
+ storeNum: string;
5759
+ storeName: string;
5760
+ icalUrl: string;
5761
+ }
5762
+ interface AppleTodaySessionList {
5763
+ storeSlug: string;
5764
+ sessions: AppleTodaySession[];
5765
+ }
5406
5766
  interface AppleNewsroomPost {
5407
5767
  title: string;
5408
5768
  category: string;
@@ -5490,15 +5850,17 @@ interface AppleCompareModels {
5490
5850
  getPurchaseOptions(urlOrPath: string): Promise<ApplePurchaseOptions>;
5491
5851
 
5492
5852
  /**
5493
- * Puts two or more iPhone models side by side on the specs apple.com itself compares them on
5494
- * screen size, chip, camera system, battery, capacity, finish, durability rating, connectivity
5495
- * straight off apple.com's own /iphone/compare/ grid. Model names must match the page's own
5496
- * naming exactly (e.g. "iPhone 17 Pro", not "17 Pro" or "iphone17pro"); an unmatched name
5497
- * throws naming the page's own list. Carries no price: apple.com's own compare page renders
5498
- * its Price row as an unfilled client-side template with no number in the static HTML, so this
5499
- * omits it rather than guess read a price off getConfigurationOptions or getPurchaseOptions
5500
- * instead. A spec absent for one model (an older phone with no Dynamic Island) is simply
5501
- * missing from that model's own list, never a false "no".
5853
+ * Puts two or more models of the SAME family Mac, iPhone, iPad or Apple Watch side by side
5854
+ * on the specs apple.com itself compares them on, straight off apple.com's own
5855
+ * /<family>/compare/ grid; which family is read off the model names themselves, never a second
5856
+ * argument. Model names must match the page's own naming exactly (e.g. "iPhone 17 Pro", not
5857
+ * "17 Pro" or "iphone17pro"; "MacBook Air 13-in. (M5)", not "MacBook Air"); an unmatched name
5858
+ * throws naming the page's own list, and names spanning two families throws too. Carries no
5859
+ * price: apple.com's own compare page renders its Price row as an unfilled client-side
5860
+ * template with no number in the static HTML, so this omits it rather than guess — read a
5861
+ * price off getConfigurationOptions or getPurchaseOptions instead. A spec absent for one model
5862
+ * (an older phone with no Dynamic Island) is simply missing from that model's own list, never
5863
+ * a false "no".
5502
5864
  */
5503
5865
  compareModels(models: string[]): Promise<AppleCompareModels>;
5504
5866
 
@@ -5558,8 +5920,13 @@ interface AppleCompareModels {
5558
5920
 
5559
5921
  /**
5560
5922
  * Reads one Apple support article end to end — the real instructions under its headline, not a
5561
- * search snippet — from the docid or URL one of searchSupport()'s own rows carries. The read
5562
- * an agent reaches for once searchSupport has narrowed the problem to one page.
5923
+ * search snippet — from the docid or URL one of searchSupport()'s own rows carries. Opens a
5924
+ * HelpKB article (docid or URL), a User Guide page ("url" field only — its own docid carries
5925
+ * no URL apple.com could resolve), and an Apple Support Community thread ("thread_<id>" docid
5926
+ * or a discussions.apple.com URL) — the last of those through a headless browser past
5927
+ * discussions.apple.com's bot-verification redirect, since it is the door Apple ranks first
5928
+ * for an ordinary problem. The read an agent reaches for once searchSupport has narrowed the
5929
+ * problem to one page.
5563
5930
  */
5564
5931
  getSupportArticle(docidOrUrl: string): Promise<AppleSupportArticle>;
5565
5932
 
@@ -5613,6 +5980,13 @@ interface AppleCompareModels {
5613
5980
  */
5614
5981
  getStore(urlOrPath: string): Promise<AppleStore>;
5615
5982
 
5983
+ /**
5984
+ * The free Today at Apple sessions one store is running, with each one's title, description,
5985
+ * start/end time and RSVP status — off the store's own calendar page. Takes a bare store slug
5986
+ * ("unionsquare") or a URL/path from listStores() or getStore()'s own rows.
5987
+ */
5988
+ listTodaySessions(storeSlugOrUrl: string): Promise<AppleTodaySessionList>;
5989
+
5616
5990
  /**
5617
5991
  * Apple's official announcements, newest first, off its own published RSS feed — every product
5618
5992
  * launch, financial result and press release, with its headline, category, publish date and
@@ -6687,6 +7061,36 @@ interface AzureListServicesResult {
6687
7061
  }
6688
7062
  }
6689
7063
 
7064
+ declare namespace BowmarkProvider_bahn {
7065
+ // ── Deutsche Bahn — Disruptions — the unit's own declarations, verbatim ──
7066
+ interface DisruptionRow {
7067
+ id: string;
7068
+ headline: string;
7069
+ begin: string; // ISO 8601 UTC
7070
+ end: string | null; // ISO 8601 UTC, null if open-ended
7071
+ cause: string; // the site's own enum, e.g. "TECHNICAL_PROBLEM_RAILWAY_SECTION"
7072
+ effect: string; // the site's own enum, e.g. "IMPAIRMENT"
7073
+ trainCategories: string[]; // e.g. ["IC", "ICE"]
7074
+ states: string[]; // German federal states affected
7075
+ affectedRoutes: string[]; // e.g. ["Mainz Hbf – Bingen(Rhein) Hbf"]
7076
+ }
7077
+
7078
+ /**
7079
+ * Lists current long-distance (ICE/IC/EC) train disruptions across the Deutsche Bahn network —
7080
+ * the same live data its verkehrslage.bahnhof.de disruption map shows, read directly off the
7081
+ * map widget's own API rather than through the client-side-rendered map.
7082
+ */
7083
+ interface Unit {
7084
+ /**
7085
+ * Lists current Deutsche Bahn long-distance (ICE/IC/EC) disruptions network-wide — cause,
7086
+ * effect, affected train categories, states and named railway sections — read live off the
7087
+ * same API bahn.de's own disruption map calls. Pass a trainCategory (e.g. "ICE") to narrow to
7088
+ * disruptions affecting that category.
7089
+ */
7090
+ listDisruptions(trainCategory?: string): Promise<DisruptionRow[]>;
7091
+ }
7092
+ }
7093
+
6690
7094
  declare namespace BowmarkProvider_bankmycell {
6691
7095
  // ── BankMyCell — the unit's own declarations, verbatim ──
6692
7096
  interface BankmycellSearchResult {
@@ -9144,6 +9548,7 @@ interface CalendlyAvailabilityResult {
9144
9548
  timezone: string;
9145
9549
  days: CalendlyDay[];
9146
9550
  otherEventTypes: CalendlyEventType[];
9551
+ unavailableReason: string | null; // non-null = Calendly says this event cannot be booked at all; days is [] BECAUSE of that, not because nothing is open
9147
9552
  }
9148
9553
 
9149
9554
  interface CalendlyFormQuestion {
@@ -9212,7 +9617,9 @@ interface CalendlyFindProfilesResult {
9212
9617
  * Returns the real, currently-open time slots for one Calendly event type — accepts a bare
9213
9618
  * profile slug ("jason-frazier"), a profile url, or a specific event url
9214
9619
  * ("https://calendly.com/jason-frazier/15min"). Given a bare profile, it picks that profile's
9215
- * first event type and reports the rest in `otherEventTypes`.
9620
+ * first event type and reports the rest in `otherEventTypes`. `days` is empty both when
9621
+ * nothing is open and when Calendly reports the calendar cannot be booked at all (a broken
9622
+ * calendar connection, a deactivated event) — check `unavailableReason` to tell the two apart.
9216
9623
  */
9217
9624
  getAvailability(profile: string, opts?: CalendlyAvailabilityOptions): Promise<CalendlyAvailabilityResult>;
9218
9625
 
@@ -11847,6 +12254,39 @@ interface CostcoProduct {
11847
12254
  }
11848
12255
  }
11849
12256
 
12257
+ declare namespace BowmarkProvider_countycourt_vic_gov_au {
12258
+ // ── County Court of Victoria — the unit's own declarations, verbatim ──
12259
+ type CountycourtListSlug = "crime-and-appeals" | "civil" | "circuit";
12260
+ interface CountycourtHearing {
12261
+ list: CountycourtListSlug;
12262
+ publishDate: string | null; // e.g. "2026-09-18"
12263
+ room: string | null; // e.g. "County Court G.1"
12264
+ judge: string | null; // e.g. "Judge Malik"
12265
+ time: string | null; // ISO timestamp
12266
+ caseId: string | null; // e.g. "AP-25-1265"
12267
+ caseName: string | null; // e.g. "HEIDARIKAKOLAKI, Amin"
12268
+ hearingType: string | null; // e.g. "For Sentence"
12269
+ partHeard: boolean;
12270
+ }
12271
+
12272
+ /**
12273
+ * Reads the County Court of Victoria's daily hearing lists — Crime and Appeals, Civil, Circuit
12274
+ * — straight off the site's own headless-Drupal JSON:API, no key, no browser.
12275
+ */
12276
+ interface Unit {
12277
+ /**
12278
+ * Returns the County Court of Victoria's currently-published daily hearing list as structured
12279
+ * rows — one row per case sitting, with its room, judge, case id, case name, hearing type,
12280
+ * listed time and part-heard flag. `list` is OPTIONAL and defaults to "crime-and-appeals"
12281
+ * (criminal trials, pleas, appeals); pass "civil" for common law and commercial hearings or
12282
+ * "circuit" for regional sittings. The site republishes each list by ~5:30pm on the day before
12283
+ * it takes effect (Melbourne time) — check `publishDate` on the returned rows rather than
12284
+ * assuming "today".
12285
+ */
12286
+ dailyList(list?: CountycourtListSlug): Promise<CountycourtHearing[]>;
12287
+ }
12288
+ }
12289
+
11850
12290
  declare namespace BowmarkProvider_couponfollow {
11851
12291
  // ── CouponFollow — the unit's own declarations, verbatim ──
11852
12292
  interface CouponFollowOffer {
@@ -12827,6 +13267,26 @@ interface DetailxpertsQuote {
12827
13267
  }
12828
13268
  }
12829
13269
 
13270
+ declare namespace BowmarkProvider_deutschepost {
13271
+ // ── Deutsche Post — the unit's own declarations, verbatim ──
13272
+ interface DialogpostRate {
13273
+ weightCategory: string;
13274
+ format: string;
13275
+ priceInCents: number;
13276
+ currency: string;
13277
+ description?: string;
13278
+ }
13279
+
13280
+ /** Dialogpost pricing for unaddressed bulk direct mail in Germany. */
13281
+ interface Unit {
13282
+ /**
13283
+ * Retrieves Deutsche Post Dialogpost pricing rates by weight and format. Returns rates for
13284
+ * unaddressed bulk direct mail delivery (household-level distribution).
13285
+ */
13286
+ getDialogpostRates(options?: { format?: string }): Promise<DialogpostRate[]>;
13287
+ }
13288
+ }
13289
+
12830
13290
  declare namespace BowmarkProvider_developersopenai {
12831
13291
  // ── OpenAI Developer Docs — the unit's own declarations, verbatim ──
12832
13292
  interface DevelopersOpenaiDocPage {
@@ -12853,6 +13313,36 @@ interface DevelopersOpenaiDocPage {
12853
13313
  }
12854
13314
  }
12855
13315
 
13316
+ declare namespace BowmarkProvider_dfs_rotogrinderssearch {
13317
+ // ── RotoGrinders — the unit's own declarations, verbatim ──
13318
+ interface SearchArgs {
13319
+ query: string;
13320
+ }
13321
+
13322
+ interface DFSProjectionRow {
13323
+ player: string;
13324
+ salary: number;
13325
+ ownership: number;
13326
+ sport?: string;
13327
+ position?: string;
13328
+ team?: string;
13329
+ }
13330
+
13331
+ interface SearchResults {
13332
+ projections: DFSProjectionRow[];
13333
+ warnings: string[];
13334
+ }
13335
+
13336
+ /** Search RotoGrinders for DFS projections, ownership percentages, and salary caps */
13337
+ interface Unit {
13338
+ /**
13339
+ * Searches RotoGrinders for DFS projections, ownership percentages, and salary caps across
13340
+ * sports (NFL, NBA, MLB, etc.)
13341
+ */
13342
+ search(args: SearchArgs): Promise<SearchResults>;
13343
+ }
13344
+ }
13345
+
12856
13346
  declare namespace BowmarkProvider_dice {
12857
13347
  // ── Dice — the unit's own declarations, verbatim ──
12858
13348
  interface DiceSearchResult {
@@ -13709,6 +14199,34 @@ interface EmbrokerQuoteEntryPoint {
13709
14199
  }
13710
14200
  }
13711
14201
 
14202
+ declare namespace BowmarkProvider_energyaustralia_com_au {
14203
+ // ── EnergyAustralia — business electricity quote — the unit's own declarations, verbatim ──
14204
+ interface EnergyaustraliaBusinessQuote {
14205
+ postcode: string;
14206
+ state: string;
14207
+ serviceable: boolean;
14208
+ plans: Array<{
14209
+ name: string;
14210
+ displayName: string;
14211
+ retailer: string;
14212
+ annualCost: number;
14213
+ monthlyEstimate: number;
14214
+ ratePerUnit: number;
14215
+ dmoReference: number;
14216
+ }>;
14217
+ }
14218
+
14219
+ /** Priced business electricity plans in a postcode's distributor territory. */
14220
+ interface Unit {
14221
+ /**
14222
+ * Returns every business electricity plan EnergyAustralia offers in a postcode's distributor
14223
+ * territory, each priced at the regulator's standard reference consumption (10,000 kWh/year) —
14224
+ * the same live call the site's own business quote page makes.
14225
+ */
14226
+ getBusinessElectricityQuote(arg0: { postcode: string }): Promise<EnergyaustraliaBusinessQuote>;
14227
+ }
14228
+ }
14229
+
13712
14230
  declare namespace BowmarkProvider_epromos {
13713
14231
  // ── ePromos — the unit's own declarations, verbatim ──
13714
14232
  // ePromos' OWN shapes — not a capability contract.
@@ -13993,6 +14511,49 @@ interface etsyListing {
13993
14511
  }
13994
14512
  }
13995
14513
 
14514
+ declare namespace BowmarkProvider_evag {
14515
+ // ── EVAG Essen — Public Transit Departures and Schedules — the unit's own declarations, verbatim ──
14516
+ interface Departure {
14517
+ line: string;
14518
+ destination: string;
14519
+ minutesUntil: number;
14520
+ platform?: string;
14521
+ delayMinutes?: number;
14522
+ }
14523
+
14524
+ interface StopSearchResult {
14525
+ id: string; // what listDepartures takes
14526
+ name: string;
14527
+ city?: string;
14528
+ }
14529
+
14530
+ interface LineStatus {
14531
+ line: string;
14532
+ status: "normal" | "disruption" | "delay";
14533
+ message?: string;
14534
+ }
14535
+
14536
+ /**
14537
+ * Real-time public transit departure information, schedules and service disruptions for Essen,
14538
+ * Germany via EVAG (Essener Verkehrs-AG) / Ruhrbahn, read straight from ifa.ruhrbahn.de's own
14539
+ * JSON backend — no key, no browser.
14540
+ */
14541
+ interface Unit {
14542
+ /**
14543
+ * Real-time departure information for a given stop — line numbers, destinations, and minutes
14544
+ * until departure. Takes the id searchStop returns. THROWS a caller-fixable error rather than
14545
+ * returning [] when ifa.ruhrbahn.de does not recognize the stop id.
14546
+ */
14547
+ listDepartures(stopId: string): Promise<Departure[]>;
14548
+
14549
+ /**
14550
+ * Search for a transit stop or city by name or partial name (e.g. 'Essen', 'Essen
14551
+ * Hauptbahnhof'); returns matching stops with the id listDepartures takes.
14552
+ */
14553
+ searchStop(query: string): Promise<StopSearchResult[]>;
14554
+ }
14555
+ }
14556
+
13996
14557
  declare namespace BowmarkProvider_eventsource {
13997
14558
  // ── Event Source — the unit's own declarations, verbatim ──
13998
14559
  interface EventSourceDesign {
@@ -16638,12 +17199,18 @@ interface SearchPlacesArgs {
16638
17199
  interface SearchPlacesResult {
16639
17200
  featureId: string;
16640
17201
  name: string;
17202
+ url: string;
16641
17203
  address: string;
16642
17204
  coordinates: { lat: number; lng: number } | null;
16643
17205
  categories: string[];
16644
17206
  rating?: number;
16645
17207
  reviewCount?: number;
16646
17208
  }
17209
+ interface SearchNearbyArgs {
17210
+ query: string;
17211
+ lat: number;
17212
+ lng: number;
17213
+ }
16647
17214
  interface GeocodeAddressArgs {
16648
17215
  address: string;
16649
17216
  }
@@ -16670,6 +17237,7 @@ interface GetPlaceArgs {
16670
17237
  interface GetPlaceResult {
16671
17238
  featureId: string;
16672
17239
  name: string;
17240
+ url: string;
16673
17241
  address: string;
16674
17242
  coordinates: { lat: number; lng: number } | null;
16675
17243
  categories: string[];
@@ -16679,6 +17247,10 @@ interface GetPlaceResult {
16679
17247
  rating?: number;
16680
17248
  reviewCount?: number;
16681
17249
  hours?: { day: string; hours: string[] }[];
17250
+ openStatus?: string;
17251
+ accessibility?: string[];
17252
+ warnings?: string[];
17253
+ businessStatus?: "closed";
16682
17254
  }
16683
17255
  interface ListReviewsArgs {
16684
17256
  query: string;
@@ -16690,6 +17262,11 @@ interface Review {
16690
17262
  text: string;
16691
17263
  relativeDate?: string;
16692
17264
  }
17265
+ interface ListReviewsResult {
17266
+ reviews: Review[];
17267
+ reviewCount?: number;
17268
+ warnings: string[];
17269
+ }
16693
17270
  interface ListRelatedPlacesArgs {
16694
17271
  query: string;
16695
17272
  }
@@ -16739,9 +17316,9 @@ interface Photo {
16739
17316
  /**
16740
17317
  * Local business search on Google Maps — find places by what a person would say, then read the
16741
17318
  * address, hours, rating, reviews, photos, co-located tenants and route. suggestPlaces
16742
- * (autocomplete), searchPlaces (the door), geocodeAddress, getPlace, listReviews, listPhotos,
16743
- * listRelatedPlaces, getDirections, resolvePlaceUrl and reverseGeocode are built; everything
16744
- * else is still a declared stub.
17319
+ * (autocomplete), searchPlaces (the door), searchNearby (the same door, anchored to a point),
17320
+ * geocodeAddress, getPlace, listReviews, listPhotos, listRelatedPlaces, getDirections,
17321
+ * resolvePlaceUrl and reverseGeocode are built; everything else is still a declared stub.
16745
17322
  */
16746
17323
  interface Unit {
16747
17324
  /**
@@ -16753,12 +17330,24 @@ interface Photo {
16753
17330
  /**
16754
17331
  * The door every other Maps function chains off. Takes what a person would say — "coffee shops
16755
17332
  * in Seattle WA", "pizza near Austin TX" — and returns the ranked places Google shows for it:
16756
- * feature id, name, address, coordinates and categories, plus rating and review count when the
16757
- * site's response carries them. The location lives in the query text; Google resolves it from
16758
- * there rather than from a separate coordinate.
17333
+ * feature id, name, address, coordinates and categories, plus rating, review count, weekly
17334
+ * hours and the site's own live open/closed line (openStatus) when the site's response carries
17335
+ * them so "which of these is open right now" costs no further call. The location lives in
17336
+ * the query text; Google resolves it from there rather than from a separate coordinate.
16759
17337
  */
16760
17338
  searchPlaces(args: SearchPlacesArgs): Promise<SearchPlacesResult[]>;
16761
17339
 
17340
+ /**
17341
+ * searchPlaces anchored to a POINT instead of resolved from the query text — for a caller
17342
+ * holding coordinates (a pin, a phone's GPS, reverseGeocode's own output) rather than a
17343
+ * locality name. Reuses reverseGeocode's own viewport template spliced into searchPlaces'
17344
+ * field mask: "coffee" anchored at a point returns results within a few hundred meters of it,
17345
+ * measured live against two cities. Same result shape as searchPlaces, hours and openStatus
17346
+ * included. Without this, a coordinate query has nowhere to go on searchPlaces and Google
17347
+ * answers from whichever city the request happens to exit near.
17348
+ */
17349
+ searchNearby(args: SearchNearbyArgs): Promise<SearchPlacesResult[]>;
17350
+
16762
17351
  /**
16763
17352
  * A street address, a city, or a business name in — the matching Google Maps place, its
16764
17353
  * feature id and its coordinates out. Rides the same door as searchPlaces (a second reading of
@@ -16780,26 +17369,44 @@ interface Photo {
16780
17369
 
16781
17370
  /**
16782
17371
  * Everything Google Maps shows on one business's panel — name, full address, coordinates,
16783
- * category, neighborhood, phone, website, rating, review count and weekly hours, each present
16784
- * only when the site's own response carried it. A THIRD reading of searchPlaces' door: takes
16785
- * the same resolving query geocodeAddress does (typically a name plus address, since this does
16786
- * not take a feature id measured live, neither the raw id nor a cid string resolves through
16787
- * this door), and throws when the query names a category or list rather than one business.
17372
+ * category, neighborhood, phone, website, rating, review count, weekly hours, the site's own
17373
+ * live open/closed line (e.g. "Closed · Opens 7 AM"), its accessibility labels (e.g.
17374
+ * "Wheelchair accessible entrance") and businessStatus, present and always "closed" ONLY when
17375
+ * the site has flagged the listing permanently closed each present only when the site's own
17376
+ * response carried it. openStatus is the site's rendered string, not a boolean this provider
17377
+ * computed — hours' display strings carry no timezone, so a caller cannot derive
17378
+ * open-right-now from them without it. accessibility is absent when the site publishes nothing
17379
+ * for that place, never a guess — the field mask carries no other amenity category (Wi-Fi,
17380
+ * outdoor seating, takeout, …) at all. businessStatus reports a CONFIRMED closure honestly
17381
+ * (measured live against Mamnoon, Plum Bistro, Harbor City Restaurant and Copine, all recently
17382
+ * closed) but its absence never means the business is open — Google does not flag every
17383
+ * real-world closure, confirmed live against two long-defunct Toys "R" Us locations that carry
17384
+ * no marker at all. This retries a few times to see past a reduced/rich flap in the site's own
17385
+ * response and merges the richest draw; `warnings` is non-empty when every attempt drew the
17386
+ * reduced record, meaning reviewCount/hours/openStatus could not be confirmed either way
17387
+ * rather than being genuinely absent. A THIRD reading of searchPlaces' door: takes the same
17388
+ * resolving query geocodeAddress does (typically a name plus address, since this does not take
17389
+ * a feature id — measured live, neither the raw id nor a cid string resolves through this
17390
+ * door), and throws when the query names a category or list rather than one business.
16788
17391
  */
16789
17392
  getPlace(args: GetPlaceArgs): Promise<GetPlaceResult>;
16790
17393
 
16791
17394
  /**
16792
17395
  * The reviews Google Maps shows on a business's own panel — a handful, each with author, star
16793
- * rating, review text and the site's own relative date; the count varies by response, so this
16794
- * retries a few times and keeps the longest list seen. A FOURTH reading of searchPlaces' door
16795
- * (the same record getPlace reads, one section further in), not the listugcposts route the
16796
- * survey planned: that route needed a session token minted by a place-page bootstrap that was
16797
- * never cracked, but the same reviews the token would have fetched are already sitting in the
16798
- * panel response. Takes the same resolving query getPlace does. Returns [] for a place with no
16799
- * reviews rather than throwing; throws only when the query itself does not resolve to one
16800
- * place.
17396
+ * rating, review text and the site's own relative date; the count of reviews RETURNED varies
17397
+ * by response, so this retries a few times and keeps the longest list seen. `reviewCount` is
17398
+ * the site's own TOTAL for the business (the same figure getPlace's own reviewCount reads),
17399
+ * present whenever any attempt carried it a caller must not read `reviews.length` as the
17400
+ * whole picture, since this is always a preview, never the full set. A FOURTH reading of
17401
+ * searchPlaces' door (the same record getPlace reads, one section further in), not the
17402
+ * listugcposts route the survey planned: that route needed a session token minted by a
17403
+ * place-page bootstrap that was never cracked, but the same reviews the token would have
17404
+ * fetched are already sitting in the panel response. Takes the same resolving query getPlace
17405
+ * does. `reviews` is [] for a place with no reviews; `warnings` says so when the site's own
17406
+ * panel reports reviews that never rendered across every attempt — a thin draw, not a
17407
+ * review-less business. Throws only when the query itself does not resolve to one place.
16801
17408
  */
16802
- listReviews(args: ListReviewsArgs): Promise<Review[]>;
17409
+ listReviews(args: ListReviewsArgs): Promise<ListReviewsResult>;
16803
17410
 
16804
17411
  /**
16805
17412
  * Other businesses Google Maps lists "At this place" — the site's own label for a shared
@@ -16878,6 +17485,7 @@ interface GoogleNewsArticle {
16878
17485
  interface GoogleNewsSearchResult {
16879
17486
  query: string;
16880
17487
  articles: GoogleNewsArticle[];
17488
+ truncatedBefore?: string;
16881
17489
  }
16882
17490
  interface GoogleNewsTopStories {
16883
17491
  title: string;
@@ -16892,6 +17500,7 @@ interface GoogleNewsPublisherHeadlines {
16892
17500
  publisher: string;
16893
17501
  query: string;
16894
17502
  articles: GoogleNewsArticle[];
17503
+ truncatedBefore?: string;
16895
17504
  }
16896
17505
  interface GoogleNewsLocalHeadlines {
16897
17506
  place: string;
@@ -16944,13 +17553,25 @@ interface GoogleNewsFullCoverage {
16944
17553
  * headline, publisher, publication time and the Google News link, newest first. `query` is
16945
17554
  * exactly what a person would type into Google News' own search box, and Google's own
16946
17555
  * operators work inside it: `when:1h`/`when:1d`/`when:7d` narrows the window,
16947
- * `site:reuters.com` pins one publisher, quotes pin a phrase and `(a OR b)` unions two
16948
- * subjects measured 2026-09-15: `site:reuters.com tesla` returned 100 items of which 100
16949
- * carried `<source>Reuters</source>`. This is the provider's main door: a caller holding only
16950
- * words gets in here. A query that matches nothing returns an empty `articles` array rather
16951
- * than throwing. `locale` `{ hl, gl, ceid }` asks for another country/language edition,
16952
- * e.g. `{ hl: "es-419", gl: "MX", ceid: "MX:es" }` for Mexico; omitted, every field defaults
16953
- * to the US English edition.
17556
+ * `after:YYYY-MM-DD`/`before:YYYY-MM-DD` pin an explicit date range, `site:reuters.com` pins
17557
+ * one publisher, quotes pin a phrase and `(a OR b)` unions two subjects measured 2026-09-15:
17558
+ * `site:reuters.com tesla` returned 100 items of which 100 carried `<source>Reuters</source>`.
17559
+ * This is the provider's main door: a caller holding only words gets in here. A query that
17560
+ * matches nothing returns an empty `articles` array rather than throwing. **This feed caps
17561
+ * around a hundred rows, newest first, with no count of its own** a `when:` window OR an
17562
+ * explicit `after:`/`before:` range wider than what fits is NOT silently cut: when the oldest
17563
+ * row served does not reach the window's or range's start, the result carries
17564
+ * `truncatedBefore` (the oldest served article's own timestamp) so a caller can tell the
17565
+ * answer stopped short (measured 2026-09-18: `"tesla when:7d"` reached only its newest 11.7h;
17566
+ * measured 2026-09-19: an 8-day `after:`/`before:` range reached only its newest ~24.5h, with
17567
+ * over a hundred articles proven missing). **Do not paste `truncatedBefore` into `before:`** —
17568
+ * it is a timestamp and `after:`/`before:` take a whole date in Google's own zone, so the
17569
+ * literal value re-asks the same range forever (measured 2026-09-19: 0 rows on the exact
17570
+ * value, or a repeating query stuck at 109 of 300 real articles). Page with the sibling field
17571
+ * `resumeBefore` instead — a date one day earlier, guaranteed to move — until a call comes
17572
+ * back with neither field. `locale` — `{ hl, gl, ceid }` — asks for another country/language
17573
+ * edition, e.g. `{ hl: "es-419", gl: "MX", ceid: "MX:es" }` for Mexico; omitted, every field
17574
+ * defaults to the US English edition.
16954
17575
  */
16955
17576
  searchNews(query: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsSearchResult>;
16956
17577
 
@@ -16979,32 +17600,45 @@ interface GoogleNewsFullCoverage {
16979
17600
  /**
16980
17601
  * Everything Google News has indexed from one publisher — `publisher` is a domain like
16981
17602
  * "reuters.com" or a name like "Reuters" — newest first, optionally narrowed with `query` the
16982
- * same way `searchNews` takes one. Built on the search door with a `site:` filter
16983
- * (`/rss/search?q=site:<publisher> <query>`), NOT on the route that looks like its own:
16984
- * `/rss/headlines/section/publication/<NAME>` answers 200 with the Top stories feed
16985
- * byte-for-byte for a name it cannot resolve, so it would look like it worked and be wrong for
16986
- * every publisher. `site:` takes a DOMAIN, so a NAME is resolved to one through the search
16987
- * door first (the host dominating that name's own search results) rather than passed straight
16988
- * to `site:`, where it is mis-parsed as a TLD plus a keyword (measured 2026-09-17: "Al
16989
- * Jazeera" returned 100 rows, all from the .al ccTLD) — a name the door cannot resolve is
16990
- * refused rather than answered with the wrong newsroom. Measured 2026-09-15: `site:reuters.com
16991
- * tesla` returned 100 items of which 100 carried a `<source>` domain on `reuters.com`.
16992
- * `locale` `{ hl, gl, ceid }` asks for another country/language edition; omitted, the US
16993
- * English one.
17603
+ * same way `searchNews` takes one, including its `when:`/`after:`/`before:` window operators.
17604
+ * Built on the search door with a `site:` filter (`/rss/search?q=site:<publisher> <query>`),
17605
+ * NOT on the route that looks like its own: `/rss/headlines/section/publication/<NAME>`
17606
+ * answers 200 with the Top stories feed byte-for-byte for a name it cannot resolve, so it
17607
+ * would look like it worked and be wrong for every publisher. `site:` takes a DOMAIN, so a
17608
+ * NAME is resolved to one through the search door first (the host dominating that name's own
17609
+ * search results) rather than passed straight to `site:`, where it is mis-parsed as a TLD plus
17610
+ * a keyword (measured 2026-09-17: "Al Jazeera" returned 100 rows, all from the .al ccTLD) — a
17611
+ * name the door cannot resolve is refused rather than answered with the wrong newsroom.
17612
+ * Measured 2026-09-15: `site:reuters.com tesla` returned 100 items of which 100 carried a
17613
+ * `<source>` domain on `reuters.com`. **Same truncation caveat as `searchNews`**: a `when:`
17614
+ * window OR an explicit `after:`/`before:` range wider than the feed's ~100-row cap is never
17615
+ * silently cut — the result carries `truncatedBefore` when more exists before that timestamp
17616
+ * (measured 2026-09-18: `listPublisherHeadlines("reuters.com", "when:7d")` reached only its
17617
+ * newest 22h; measured 2026-09-19: an 8-day `after:`/`before:` range reached only its newest
17618
+ * ~24.5h). **Do not paste `truncatedBefore` into `before:`** — page with the sibling field
17619
+ * `resumeBefore` instead, exactly as `searchNews` does; the timestamp re-asks the same range
17620
+ * forever. `locale` — `{ hl, gl, ceid }` — asks for another country/language edition; omitted,
17621
+ * the US English one.
16994
17622
  */
16995
17623
  listPublisherHeadlines(publisher: string, query?: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsPublisherHeadlines>;
16996
17624
 
16997
17625
  /**
16998
17626
  * What is being reported in one place — the local-news edition for a city or region, by NAME
16999
- * ("Seattle", "San Francisco"), not a place id. There is no closed list of valid places, so a
17000
- * place Google News has no edition for is refused only after the request comes back: it
17001
- * answers 200 with an in-protocol "This feed is not available." sentinel item and a bare
17002
- * "Google News" channel title rather than the place's own name (measured 2026-09-15 on a
17627
+ * ("Seattle", "San Francisco"), NOT a ZIP or postal code. There is no closed list of valid
17628
+ * places, so a place Google News has no edition for is refused only after the request comes
17629
+ * back: it answers 200 with an in-protocol "This feed is not available." sentinel item and a
17630
+ * bare "Google News" channel title rather than the place's own name (measured 2026-09-15 on a
17003
17631
  * nonsense place; the same sentinel `_client` already drops out of every other feed by guid) —
17004
- * reading that as an empty result would be silently wrong, so this throws instead. A
17005
- * recognized place's own channel title is echoed back in `place`, in the site's own spelling,
17006
- * so `"seattle"` and `"Seattle"` both resolve to `"Seattle"`. `locale` `{ hl, gl, ceid }` —
17007
- * asks for another country/language edition; omitted, the US English one.
17632
+ * reading that as an empty result would be silently wrong, so this throws instead. A US ZIP
17633
+ * code gets a second, quieter version of the same failure: Google mints a place-shaped channel
17634
+ * for it too ("94103 - Latest - Google News") but with zero headlines, which would otherwise
17635
+ * read as a genuinely quiet news day — measured 2026-09-18, four dense-metro ZIPs all answered
17636
+ * 0 while "Seattle" answered 70 in the same run, and every real place swept (however small)
17637
+ * resolved to at least one headline, so a place-shaped channel with zero items is refused too,
17638
+ * naming a city as the fix. A recognized place's own channel title is echoed back in `place`,
17639
+ * in the site's own spelling, so `"seattle"` and `"Seattle"` both resolve to `"Seattle"`.
17640
+ * `locale` — `{ hl, gl, ceid }` — asks for another country/language edition; omitted, the US
17641
+ * English one.
17008
17642
  */
17009
17643
  listLocalHeadlines(place: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsLocalHeadlines>;
17010
17644
 
@@ -17026,8 +17660,10 @@ interface GoogleNewsFullCoverage {
17026
17660
  * exit made the request) — each with the opaque topic id `getTopicHeadlines` takes. Read off
17027
17661
  * the home page's own embedded `AF_initDataCallback({key: 'ds:2'…})` state rather than scraped
17028
17662
  * from the rendered nav, so it needs no browser. The finder that makes a topic id reachable by
17029
- * somebody who only holds words. `locale` `{ hl, gl, ceid }` asks for another
17030
- * country/language edition's own nav rail; omitted, the US English one.
17663
+ * somebody who only holds words. The "Your local news" entry's id is NOT a topic feed — the
17664
+ * site serves it by geo-locating the reader so `getTopicHeadlines` and `listStories` both
17665
+ * refuse it and name `listLocalHeadlines` instead. `locale` — `{ hl, gl, ceid }` — asks for
17666
+ * another country/language edition's own nav rail; omitted, the US English one.
17031
17667
  */
17032
17668
  listTopics(locale?: GoogleNewsLocaleArg): Promise<GoogleNewsTopic[]>;
17033
17669
 
@@ -17038,13 +17674,17 @@ interface GoogleNewsFullCoverage {
17038
17674
  * `/rss/headlines/section/topic/<NAME>`) — the only difference is the key, since a topic id
17039
17675
  * has no canonical spelling for the site to correct it to. Measured 2026-09-15: the Technology
17040
17676
  * section's own topic id answers the identical feed shape as its section-name door, 70 items,
17041
- * titled "Technology - Latest - Google News". THE ONLY IDS REACHABLE WITHOUT AN ACCOUNT ARE
17042
- * THE NINE `listTopics` RETURNS. Google News also runs entity and interest topics (a company,
17043
- * a person, a sports league), but measured 2026-09-16 nothing logged-out hands their ids out —
17044
- * a topic page, a story page, `/home` and `/publications` each carry only the nav rail's own
17045
- * nine, and the HTML `/search` page that renders the entity's Follow chip answers 429 through
17046
- * the proxy. To follow a company or a person today, use `searchNews`. `locale` `{ hl, gl,
17047
- * ceid }`asks for another country/language edition; omitted, the US English one.
17677
+ * titled "Technology - Latest - Google News". EIGHT OF THE NINE `listTopics` IDS ARE REACHABLE
17678
+ * WITHOUT AN ACCOUNT; the ninth "Your local news" is refused before any request, since the
17679
+ * site serves it by geo-locating the reader rather than from a topic feed (measured
17680
+ * 2026-09-17: that id 404s here and returns zero stories from `listStories`, with no error).
17681
+ * Call `listLocalHeadlines("<city>")` for that entry instead. Google News also runs entity and
17682
+ * interest topics (a company, a person, a sports league), but measured 2026-09-16 nothing
17683
+ * logged-out hands their ids out a topic page, a story page, `/home` and `/publications`
17684
+ * each carry only the nav rail's own nine, and the HTML `/search` page that renders the
17685
+ * entity's Follow chip answers 429 through the proxy. To follow a company or a person today,
17686
+ * use `searchNews`. `locale` — `{ hl, gl, ceid }` — asks for another country/language edition;
17687
+ * omitted, the US English one.
17048
17688
  */
17049
17689
  getTopicHeadlines(topicId: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsTopicFeed>;
17050
17690
 
@@ -17056,9 +17696,14 @@ interface GoogleNewsFullCoverage {
17056
17696
  * instead, which surfaces far fewer (2 measured) since most front-page items are
17057
17697
  * single-outlet. Reads the "Full Coverage" anchor Google News renders on every multi-outlet
17058
17698
  * story directly off the page's HTML, rather than the page's own embedded state — no RSS feed
17059
- * on this site emits a story id at all, so this is the only door. `locale` — `{ hl, gl, ceid
17060
- * }` asks for another country/language edition of whichever page is read; omitted, the US
17061
- * English one.
17699
+ * on this site emits a story id at all, so this is the only door. A `topicId` from
17700
+ * `listTopics`' "Your local news" entry is refused before any request that entry is not a
17701
+ * topic feed; call `listLocalHeadlines("<city>")` instead (measured 2026-09-17: without this
17702
+ * check the id silently answered 200 with zero stories). `locale` — `{ hl, gl, ceid }` — asks
17703
+ * for another country/language edition of whichever page is read; omitted, the US English one.
17704
+ * The `storyId` each result carries has that same edition baked in, so passing it straight
17705
+ * into `getFullCoverage` with no `locale` argument reads the right edition automatically — see
17706
+ * `getFullCoverage`'s own note.
17062
17707
  */
17063
17708
  listStories(topicId?: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsStory[]>;
17064
17709
 
@@ -17075,8 +17720,12 @@ interface GoogleNewsFullCoverage {
17075
17720
  * already carries its own publisher URL: the STORY PAGE ITSELF is read in whichever edition is
17076
17721
  * asked for, and reading it in the wrong one silently truncates or empties the coverage
17077
17722
  * (measured 2026-09-16: the same story id answered 0 articles under the US default and 53
17078
- * under `{ hl: "es-419", gl: "MX", ceid: "MX:es" }`). Pass the SAME locale the `listStories`
17079
- * call that produced this id used; omitted, the US English edition.
17723
+ * under `{ hl: "es-419", gl: "MX", ceid: "MX:es" }`). A `storyId` FROM `listStories` already
17724
+ * carries the edition it was found under, so leaving `locale` unset here reads that SAME
17725
+ * edition automatically — pass an explicit `locale` only to read a story you found some other
17726
+ * way, and it must agree with the id's own encoded edition or the call is refused rather than
17727
+ * silently truncated (measured live 2026-09-17: a wrong edition can render a place or topic
17728
+ * label that reads like a real headline).
17080
17729
  */
17081
17730
  getFullCoverage(storyId: string, locale?: GoogleNewsLocaleArg): Promise<GoogleNewsFullCoverage>;
17082
17731
  }
@@ -22296,6 +22945,80 @@ interface LegacyHomesalCommunity {
22296
22945
  }
22297
22946
  }
22298
22947
 
22948
+ declare namespace BowmarkProvider_letterboxd {
22949
+ // ── Letterboxd — the unit's own declarations, verbatim ──
22950
+ interface LetterboxdFilm {
22951
+ slug: string;
22952
+ title: string;
22953
+ year: number | null;
22954
+ url: string;
22955
+ directors: string[];
22956
+ cast: string[];
22957
+ genres: string[];
22958
+ countries: string[];
22959
+ languages: string[];
22960
+ runtimeMinutes: number | null;
22961
+ description: string | null;
22962
+ posterUrl: string | null;
22963
+ averageRating: number | null;
22964
+ ratingCount: number | null;
22965
+ reviewCount: number | null;
22966
+ }
22967
+
22968
+ interface LetterboxdMemberFilm {
22969
+ slug: string;
22970
+ title: string;
22971
+ year: number | null;
22972
+ url: string;
22973
+ }
22974
+
22975
+ interface LetterboxdDiaryEntry {
22976
+ filmTitle: string;
22977
+ filmYear: number | null;
22978
+ slug: string;
22979
+ url: string;
22980
+ rating: number | null;
22981
+ watchedDate: string | null;
22982
+ rewatch: boolean;
22983
+ liked: boolean;
22984
+ publishedAt: string | null;
22985
+ reviewText: string | null;
22986
+ }
22987
+
22988
+ /**
22989
+ * The social network for film. Reads one film's full record including letterboxd's own
22990
+ * weighted average rating over millions of members, the films a member has logged, and a
22991
+ * member's diary with their star ratings and full review text — all browserless. Also the
22992
+ * library's first provider that can CREATE its own account: signUp drives the real
22993
+ * registration form, solves its hCaptcha and verifies the account from the persona's inbox.
22994
+ */
22995
+ interface Unit {
22996
+ /**
22997
+ * Reads one film's full record — pass the slug from its letterboxd URL, e.g. { slug:
22998
+ * "parasite-2019" }. Returns title, year, directors, cast, genres, countries, languages,
22999
+ * runtime, synopsis and poster, plus `averageRating` (letterboxd's weighted average, 0.5-5),
23000
+ * `ratingCount` and `reviewCount`. That rating is computed over millions of member ratings and
23001
+ * is published nowhere else.
23002
+ */
23003
+ film(args: { slug: string }): Promise<LetterboxdFilm>;
23004
+
23005
+ /**
23006
+ * Lists the films a member has logged, newest first — { member: "davidehrlich" }, with `limit`
23007
+ * capping rows (default 72, max 200). Returns slug, title, year and URL per film, which is
23008
+ * what `film` takes to go deeper on any one of them.
23009
+ */
23010
+ memberFilms(args: { member: string, limit?: number }): Promise<LetterboxdMemberFilm[]>;
23011
+
23012
+ /**
23013
+ * Reads a member's activity feed: every film they logged, with their own star rating, the date
23014
+ * they watched it, whether it was a rewatch, whether they liked it, and the full text of any
23015
+ * review they wrote. The review prose is the part no listing page carries. List and like
23016
+ * activity is skipped.
23017
+ */
23018
+ memberDiary(args: { member: string, limit?: number }): Promise<LetterboxdDiaryEntry[]>;
23019
+ }
23020
+ }
23021
+
22299
23022
  declare namespace BowmarkProvider_linkedin {
22300
23023
  // ── LinkedIn — the unit's own declarations, verbatim ──
22301
23024
  interface LinkedinJobSearchResult {
@@ -26329,6 +27052,51 @@ interface OnTheMarketProperty {
26329
27052
  }
26330
27053
  }
26331
27054
 
27055
+ declare namespace BowmarkProvider_originenergy_com_au {
27056
+ // ── Origin Energy — the unit's own declarations, verbatim ──
27057
+ // Origin Energy's OWN shapes — not a capability contract.
27058
+
27059
+ interface OriginBusinessElectricityPlan {
27060
+ title: string;
27061
+ code: string; // e.g. "E_SMEGOVARIABLEOG_8PC_VAR_AUSGRID_260701_CP"
27062
+ description: string;
27063
+ contractPeriod: number | null;
27064
+ distributor: string | null; // e.g. "Ausgrid Operations Partnership"
27065
+ tariffName: string | null; // e.g. "Business, single rate"
27066
+ referenceUsage: string; // e.g. "10000 kWh / yearly"
27067
+ annualCost: number | null;
27068
+ monthlyCost: number | null;
27069
+ referenceCost: number | null; // the DMO/VDO benchmark this plan compares against
27070
+ percentSavingVsReference: number | null;
27071
+ isRegulated: boolean;
27072
+ }
27073
+
27074
+ interface OriginBusinessElectricityQuote {
27075
+ postcode: string;
27076
+ state: string; // derived from the postcode, not asked of the caller
27077
+ serviceable: boolean; // false where Origin does not retail electricity (e.g. WA, TAS, NT)
27078
+ plans: OriginBusinessElectricityPlan[];
27079
+ }
27080
+
27081
+ interface OriginBusinessElectricityQuoteArgs { postcode: string }
27082
+
27083
+ /**
27084
+ * originenergy.com.au business electricity quote — every plan Origin Energy offers in a
27085
+ * postcode's distributor territory, priced at the regulator's standard reference consumption,
27086
+ * the same live call the site's own 'Compare business plans' page makes.
27087
+ */
27088
+ interface Unit {
27089
+ /**
27090
+ * Returns every business electricity plan Origin Energy offers in a postcode's distributor
27091
+ * territory, each priced at the regulator's standard reference consumption (10,000 kWh/year) —
27092
+ * the same live call the site's own 'Compare business plans' page makes. `serviceable: false`
27093
+ * with an empty `plans` array is Origin's own honest answer for a postcode it does not retail
27094
+ * electricity into (WA, TAS, NT), not a failure.
27095
+ */
27096
+ getBusinessElectricityQuote(arg0: OriginBusinessElectricityQuoteArgs): Promise<OriginBusinessElectricityQuote>;
27097
+ }
27098
+ }
27099
+
26332
27100
  declare namespace BowmarkProvider_othership {
26333
27101
  // ── Othership — the unit's own declarations, verbatim ──
26334
27102
  // Othership's OWN shapes — not a capability contract.
@@ -26652,6 +27420,62 @@ interface PacificLifestyleHomesListing { id: string; address: string; city: stri
26652
27420
  }
26653
27421
  }
26654
27422
 
27423
+ declare namespace BowmarkProvider_packlane {
27424
+ // ── Packlane — the unit's own declarations, verbatim ──
27425
+ type MailerBoxSize = "5x3x1.5" | "6x4x3" | "6x5x2.25" | "7x5x3" | "8x6x3" | "9x6x4"
27426
+ | "9x7x2.25" | "9.5x7.75x4" | "10x8x4" | "11.25x9x3" | "12x9x2" | "12x10x4" | "13x10x5" | "14x10x4";
27427
+ type MailerBoxMaterial = "white" | "white-b-flute" | "dreamcoat" | "dreamcoat-b-flute" | "kraft" | "kraft-b-flute";
27428
+ type PrintSidesOption = "both-sides" | "outside" | "inside" | "blank";
27429
+
27430
+ interface GetQuoteArgs {
27431
+ size: MailerBoxSize;
27432
+ material: MailerBoxMaterial;
27433
+ printSides: PrintSidesOption;
27434
+ quantity: number;
27435
+ }
27436
+
27437
+ interface packlaneQuote {
27438
+ size: MailerBoxSize;
27439
+ material: MailerBoxMaterial;
27440
+ printSides: PrintSidesOption;
27441
+ quantity: number;
27442
+ unitPrice: { amount: number; currency: string };
27443
+ totalPrice: { amount: number; currency: string };
27444
+ sku: string;
27445
+ itemName: string;
27446
+ turnaroundDays: number;
27447
+ }
27448
+
27449
+ /** Instant custom Mailer Box quotes from packlane.com. */
27450
+ interface Unit {
27451
+ /**
27452
+ * Prices a custom Mailer Box (size, material, printed sides, quantity) via packlane.com's own
27453
+ * on-page calculator API.
27454
+ */
27455
+ getQuote(args: GetQuoteArgs): Promise<packlaneQuote>;
27456
+ }
27457
+ }
27458
+
27459
+ declare namespace BowmarkProvider_pawsup {
27460
+ // ── Paws Up — the unit's own declarations, verbatim ──
27461
+ interface AvailabilityResult {
27462
+ available: boolean;
27463
+ accommodationType?: string;
27464
+ pricePerNight?: number;
27465
+ currency: string;
27466
+ checkInDate: string;
27467
+ checkOutDate: string;
27468
+ guests: number;
27469
+ warnings?: string[];
27470
+ }
27471
+
27472
+ /** Luxury glamping resort availability and accommodations on Paws Up's booking portal. */
27473
+ interface Unit {
27474
+ /** Checks available accommodations and starting rates for a requested stay at Paws Up. */
27475
+ checkAvailability(args: { checkInDate: string; checkOutDate: string; guests?: number }): Promise<AvailabilityResult>;
27476
+ }
27477
+ }
27478
+
26655
27479
  declare namespace BowmarkProvider_paypal {
26656
27480
  // ── PayPal — the unit's own declarations, verbatim ──
26657
27481
  interface PaypalEstimateFeeArgs {
@@ -27242,6 +28066,26 @@ interface PizzahutDealsForRender {
27242
28066
  }
27243
28067
  }
27244
28068
 
28069
+ declare namespace BowmarkProvider_planning_inspectorate_ni {
28070
+ // ── Planning Inspectorate — National Infrastructure Planning — the unit's own declarations, verbatim ──
28071
+ interface PlanningInspectorateProject {
28072
+ id: string;
28073
+ name: string;
28074
+ applicant?: string;
28075
+ stage?: string;
28076
+ url: string;
28077
+ }
28078
+
28079
+ /** Search the UK national infrastructure planning register by project name. */
28080
+ interface Unit {
28081
+ /**
28082
+ * Searches the UK national infrastructure planning register by project name or keywords,
28083
+ * returns matching projects with their id, name and register URL.
28084
+ */
28085
+ search(query: string): Promise<PlanningInspectorateProject[]>;
28086
+ }
28087
+ }
28088
+
27245
28089
  declare namespace BowmarkProvider_platform_claude_com {
27246
28090
  // ── Claude Developer Platform Docs — the unit's own declarations, verbatim ──
27247
28091
  interface platform_claude_comDoc {
@@ -27429,6 +28273,39 @@ interface positivegridRetailerSearch {
27429
28273
  }
27430
28274
  }
27431
28275
 
28276
+ declare namespace BowmarkProvider_postcard_direct_mail {
28277
+ // ── Direct Mail Postcard Quotes — the unit's own declarations, verbatim ──
28278
+ interface GetQuoteArgs {
28279
+ quantity: number
28280
+ size?: string
28281
+ stock?: string
28282
+ }
28283
+
28284
+ interface PostcardQuoteLineItem {
28285
+ size: string
28286
+ stock: string
28287
+ totalPrice: number
28288
+ unitPrice: number
28289
+ currency: string
28290
+ }
28291
+
28292
+ interface PostcardDirectMailQuoteResponse {
28293
+ quantity: number
28294
+ lineItems: PostcardQuoteLineItem[]
28295
+ estimatedDeliveryDays?: number
28296
+ warnings: string[]
28297
+ }
28298
+
28299
+ /** Get postcard printing quotes with pricing by quantity, size, and stock. */
28300
+ interface Unit {
28301
+ /**
28302
+ * Returns pricing for direct mail postcards at the requested quantity with optional size and
28303
+ * stock.
28304
+ */
28305
+ getQuote(args: GetQuoteArgs): Promise<PostcardDirectMailQuoteResponse>;
28306
+ }
28307
+ }
28308
+
27432
28309
  declare namespace BowmarkProvider_postiz {
27433
28310
  // ── Postiz — the unit's own declarations, verbatim ──
27434
28311
  interface PostizPost {
@@ -27466,6 +28343,33 @@ interface CreatePostArgs {
27466
28343
  }
27467
28344
  }
27468
28345
 
28346
+ declare namespace BowmarkProvider_powys {
28347
+ // ── Powys planning applications — the unit's own declarations, verbatim ──
28348
+ interface powysApplication {
28349
+ reference: string;
28350
+ description: string;
28351
+ address: string;
28352
+ applicant: string;
28353
+ dateSubmitted: string;
28354
+ status: string; // the site's own labels — read the values off a result, never guess one from prose
28355
+ decision?: string;
28356
+ }
28357
+
28358
+ interface powysSearchResult {
28359
+ results: powysApplication[];
28360
+ }
28361
+
28362
+ /** Search Powys County Council planning applications by reference, address, or description. */
28363
+ interface Unit {
28364
+ /**
28365
+ * Searches Powys County Council planning applications. Takes a required search term or
28366
+ * reference (e.g., 'P/2024/0123' for a reference or 'Main Street' for an address) and returns
28367
+ * matching applications with their status and decision details.
28368
+ */
28369
+ search(query: string): Promise<powysSearchResult>;
28370
+ }
28371
+ }
28372
+
27469
28373
  declare namespace BowmarkProvider_premierbuildings {
27470
28374
  // ── Premier Portable Buildings — the unit's own declarations, verbatim ──
27471
28375
  interface PremierbuildingsStyle {
@@ -27663,6 +28567,7 @@ interface PrimeVideoCategory {
27663
28567
  interface PrimeVideoCategoryRow {
27664
28568
  heading: string;
27665
28569
  titles: PrimeVideoTitle[];
28570
+ nextPage?: string;
27666
28571
  }
27667
28572
  interface PrimeVideoTop10Entry extends PrimeVideoTitle {
27668
28573
  position: number;
@@ -27729,21 +28634,15 @@ interface PrimeVideoLiveSportsEvent {
27729
28634
  * function here takes, whether it is a film or a series, the year, the maturity rating, and
27730
28635
  * the site's own sentence for how to watch it. THE provider's door: every titleId-taking
27731
28636
  * function below is fed by this one. Returns the FIRST page only — Prime Video's search page
27732
- * carries no pagination markers at all (measured 2026-09-15). `options.waysToWatch` narrows by
27733
- * how you can watch it "prime" (included with a Prime membership), "channels" (an add-on
27734
- * subscription) or "rentOrBuy" the commonest thing a viewer does after typing a query and
27735
- * the one refinement built so far. The site's other five refinement dimensions (which channel,
27736
- * HD/UHD, theme, subtitle language, film-or-series) are still not built here: every one of
27737
- * them rides the same opaque per-page `serviceToken` mechanism (rung 11 an undocumented
27738
- * endpoint reached by harvesting the token off the page a search already returned), never a
27739
- * query parameter, and a hand-constructed query parameter silently returns the unfiltered set
27740
- * rather than erroring. A query that matches nothing returns an empty array rather than
27741
- * throwing. A filtered call whose real matches are too few can carry the site's own generic
27742
- * recommendations under a heading still labelled "Top results" — measured 2026-09-16, not a
27743
- * defect in this parser: the site does this identically on the unfiltered page's own "More to
27744
- * explore" row.
27745
- */
27746
- searchTitles(query: string, options?: { waysToWatch?: "prime" | "channels" | "rentOrBuy" }): Promise<PrimeVideoTitle[]>;
28637
+ * carries no pagination markers at all (measured 2026-09-15). This function took a
28638
+ * `waysToWatch` refinement option for one day (2026-09-16 to 2026-09-17) it was WITHDRAWN
28639
+ * after the `qa` pass found the whole "Ways to Watch" refinement block gone from the
28640
+ * logged-out search page, confirmed on two fresh live captures and a real browser (no
28641
+ * `filters`/`p_n_ways_to_watch`/`serviceToken` anywhere in the hydration script or the
28642
+ * rendered DOM; only an unrelated "Free to me" filter survives). A query that matches nothing
28643
+ * returns an empty array rather than throwing.
28644
+ */
28645
+ searchTitles(query: string): Promise<PrimeVideoTitle[]>;
27747
28646
 
27748
28647
  /**
27749
28648
  * Ask Prime Video's own search box what it would autocomplete a prefix to — "the boy" comes
@@ -27771,9 +28670,11 @@ interface PrimeVideoLiveSportsEvent {
27771
28670
  * rent or buy — and when it is rent-or-buy, every offer with its real price and quality. THE
27772
28671
  * question this provider exists to answer, and the one no general search result answers about
27773
28672
  * Amazon's catalogue. Takes a titleId or a title URL, e.g. one read off searchTitles() or
27774
- * getTitle(). Reads the SAME page as getTitle, never fetches it twice. Placing any of these
27775
- * orders is never a function of this provider — a flow that costs money stops before the
27776
- * payment step, always.
28673
+ * getTitle(). Reads the SAME page as getTitle, never fetches it twice. A `subscribe` offer's
28674
+ * `channel.benefitId` is the same slug listChannels() surfaces as `benefit` — a best-effort
28675
+ * join, not a guaranteed one, see listChannels()'s own doc for the measured exception. Placing
28676
+ * any of these orders is never a function of this provider — a flow that costs money stops
28677
+ * before the payment step, always.
27777
28678
  */
27778
28679
  getWatchOptions(titleId: string): Promise<PrimeVideoWatchOptions>;
27779
28680
 
@@ -27829,8 +28730,13 @@ interface PrimeVideoLiveSportsEvent {
27829
28730
  * own order, with the same fields searchTitles() returns. Takes a `path` off listCategories(),
27830
28731
  * e.g. "/genre/comedy", "/collection/streamfree", "/movie", "/tv" or "/store" — those five are
27831
28732
  * the only shapes this pass measured. Drops the leading, unheaded hero carousel every
27832
- * storefront page opens with; every other row is real. Returns the FIRST page only, exactly
27833
- * like searchTitles() — these pages carry no pagination markers either.
28733
+ * storefront page opens with; every other row is real. **A row carrying more than the 20
28734
+ * titles returned here has `nextPage`** (read the field's own doc) — pass it straight back to
28735
+ * this function to read the next page. That page is genuinely new (measured: at most one
28736
+ * overlapping title, at the boundary), and it never carries its own further `nextPage`, so
28737
+ * this reaches one hop past the first 20, honestly, not an unbounded walk. `searchTitles()`
28738
+ * carries no such field — its results page publishes no pagination markers at all (measured
28739
+ * 2026-09-15), and that absence is a fact about search specifically.
27834
28740
  */
27835
28741
  listCategoryTitles(path: string): Promise<PrimeVideoCategoryRow[]>;
27836
28742
 
@@ -27891,31 +28797,49 @@ interface PrimeVideoLiveSportsEvent {
27891
28797
 
27892
28798
  /**
27893
28799
  * List the add-on subscriptions Prime Video sells inside itself — HBO Max, Paramount+,
27894
- * Britbox, ViX Premium and seventy-odd more — with the two ids each one is addressed by:
28800
+ * Britbox, ViX Premium and a hundred-odd more — with the ids each one is addressed by:
27895
28801
  * `channelId`, which opens the channel's own page (getChannel(), listTop10("channel",
27896
- * channelId)), and `benefitId`, which `GET /offers?benefitId=<benefitId>` takes to start a
27897
- * subscription. The door for getChannel() and the thing that turns getWatchOptions' "get an
27898
- * add-on subscription" into a named service a person can decide about. No arguments `GET
27899
- * /addons`, read off the "Subscriptions you might like" row with the shared hydration parser.
27900
- * **Carries no price.** The two dollar strings on the whole page are a card's own compact
27901
- * offer wording, never a clean number, so `offerMessage` carries the site's own sentence
27902
- * instead. Most cards carry both ids; a card with no channel page of its own (CNN All Access)
27903
- * carries only `benefitId`, and one further outlier (NBA League Pass, a subscription pass
27904
- * rather than a channel) carries neither both real, measured gaps, never a guess.
28802
+ * channelId)); `benefitId`, which `GET /offers?benefitId=<benefitId>` takes to start a
28803
+ * subscription; and `benefit`, the slug that also names which add-on a title's
28804
+ * getWatchOptions() subscribe offer needs (`offers[].channel.benefitId`) **the ONLY field
28805
+ * that joins the two halves of this provider**, and a best-effort one, see its own doc for the
28806
+ * measured miss. The door for getChannel() and the thing that turns getWatchOptions' "get an
28807
+ * add-on subscription" into a named service a person can decide about. No arguments — reads
28808
+ * BOTH `GET /storefront/subscription/default` (the site's own categorized shop, deterministic,
28809
+ * ~102 channels across six categories, each addressed by a `benefit` slug but carrying no
28810
+ * `channelId`/`benefitId`) and `GET /addons` (a rotating shelf of ~80, the only source for
28811
+ * `channelId`/`benefitId`, and offerMessage), merged so a channel present on either carries
28812
+ * the fullest card either door gave it. **Neither door alone was ever complete** — measured
28813
+ * 2026-09-18, the storefront door found 44 channels the addons shelf's shorter rotation
28814
+ * missed, and the addons shelf found 22 the storefront door's own categorization missed
28815
+ * (Peacock Premium Plus, NBA League Pass, Tennis Channel, MLB Network among them) — so this is
28816
+ * the union, not either one. **Still not exhaustive**: one storefront category
28817
+ * ("Entertainment") is short 2 of 22 cards behind its own unbuilt pagination cursor. **Carries
28818
+ * no price.** The dollar strings on either page are a card's own compact offer wording, never
28819
+ * a clean number, so `offerMessage` carries the site's own sentence instead when the card has
28820
+ * one. Most `/addons`-sourced cards carry both `channelId` and `benefitId`; a card with no
28821
+ * channel page of its own (CNN All Access) carries only `benefitId`; a card reached only
28822
+ * through the storefront door carries neither — all real, measured gaps, never a guess.
27905
28823
  */
27906
28824
  listChannels(): Promise<PrimeVideoChannel[]>;
27907
28825
 
27908
28826
  /**
27909
28827
  * Read one add-on channel: what it is called, its top ten, its originals and series, and the
27910
28828
  * live events it is carrying — the rest of a channel's catalogue, for answering "is it worth
27911
- * subscribing to this to watch that" rather than one title. Takes the channel's uuid off
27912
- * listChannels(), e.g. one read off `channelId` there NOT the same card's `benefitId`, which
27913
- * opens a different route. `GET /channel/<uuid>`, read off the same carousel parser
27914
- * listCategoryTitles() uses: a heading and every title under it, per row, in the site's own
27915
- * order. `rows` never includes the channel's own hero banner, which carries no title list of
27916
- * its own.
27917
- */
27918
- getChannel(channelId: string): Promise<PrimeVideoChannelDetail>;
28829
+ * subscribing to this to watch that" rather than one title. Takes EITHER of the site's two
28830
+ * doors: the channel's uuid off listChannels() (its `channelId`, or a `/channel/<uuid>` URL)
28831
+ * `GET /channel/<uuid>` OR its benefit slug off a title's own subscribe offer
28832
+ * (getWatchOptions().offers[].channel.benefitId, or its `/storefront/subscription/<slug>` link
28833
+ * pass that link straight through, no join needed) `GET /storefront/subscription/<slug>`.
28834
+ * Both routes read the same carousel parser listCategoryTitles() uses: a heading and every
28835
+ * title under it, per row, in the site's own order. `rows` never includes the channel's own
28836
+ * hero banner, which carries no title list of its own. Widened because listChannels()'s
28837
+ * `/addons`-sourced cards are only a rotating slice of the shop, and its storefront-sourced
28838
+ * cards carry no `channelId` at all (see its own summary) — a slug a title names is often
28839
+ * absent from any card a caller could join against, so the slug door needs no `listChannels()`
28840
+ * round-trip at all.
28841
+ */
28842
+ getChannel(channel: string): Promise<PrimeVideoChannelDetail>;
27919
28843
 
27920
28844
  /**
27921
28845
  * List the free live TV ("livetv", off `/livetv`) or news ("news", off `/news`) stations Prime
@@ -27963,6 +28887,20 @@ interface PrimeVideoLiveSportsEvent {
27963
28887
  * failure.
27964
28888
  */
27965
28889
  listLiveSports(): Promise<PrimeVideoLiveSportsEvent[]>;
28890
+
28891
+ /**
28892
+ * What to watch next after this one — the commonest thing anyone says after the credits roll,
28893
+ * and the one ordinary catalogue question the rest of this provider cannot answer at all:
28894
+ * searching the film's own name (searchTitles()) returns its sequels, not a recommendation.
28895
+ * Takes a titleId or a title URL, e.g. one read off searchTitles() or getTitle(). Reads the
28896
+ * SAME cached page as getTitle, never fetches it twice. Returns one row per carousel the
28897
+ * detail page carries below the fold — typically "Customers also watched" (real titles, not
28898
+ * the one just watched or its own sequels) and, when the title belongs to one, "Explore the …
28899
+ * collection" for the rest of the franchise — in the SAME shape listCategoryTitles() returns,
28900
+ * so a caller reads both the same way. A title with no such rows on its page returns an empty
28901
+ * array, a real, if unlikely, answer.
28902
+ */
28903
+ listRelatedTitles(titleId: string): Promise<PrimeVideoCategoryRow[]>;
27966
28904
  }
27967
28905
  }
27968
28906
 
@@ -34281,9 +35219,8 @@ interface ShippingBoxPrice {
34281
35219
  }
34282
35220
 
34283
35221
  /**
34284
- * Prices Vistaprint's Full-Print Shipping Boxes for a real size, print area and quantity — the
34285
- * live, quantity-tiered price the site's own PDP configurator computes, with no browser,
34286
- * account or cart. Custom printed boxes, mailer boxes and packaging boxes.
35222
+ * Prices Vistaprint's Full-Print Shipping Boxes real, quantity-tiered pricing the site's own
35223
+ * PDP configurator computes, with no browser, account or cart.
34287
35224
  */
34288
35225
  interface Unit {
34289
35226
  /**
@@ -34708,6 +35645,38 @@ interface wellfoundCompanyDetail {
34708
35645
  }
34709
35646
  }
34710
35647
 
35648
+ declare namespace BowmarkProvider_wholefoodsmarket {
35649
+ // ── Whole Foods — the unit's own declarations, verbatim ──
35650
+ interface Product {
35651
+ id: string;
35652
+ name: string;
35653
+ price?: number;
35654
+ unit?: string;
35655
+ }
35656
+
35657
+ interface SearchResults {
35658
+ products: Product[];
35659
+ warnings: string[];
35660
+ }
35661
+
35662
+ /**
35663
+ * Search Whole Foods product catalog by a SPECIFIC product or category name (e.g. 'organic
35664
+ * apples'). The store name alone ('whole foods') is not a valid query — it requires a product
35665
+ * to search for.
35666
+ */
35667
+ interface Unit {
35668
+ /**
35669
+ * ⚠️ REQUIRED: This function ONLY accepts a SPECIFIC product or category search query (e.g.
35670
+ * 'organic apples', 'sourdough bread'). The store name 'Whole Foods' alone IS NOT A VALID
35671
+ * QUERY. You MUST have a product name from the caller before calling this. If caller only said
35672
+ * 'Whole Foods' with no product: STOP. Ask the caller FIRST: 'What specific product would you
35673
+ * like me to search for at Whole Foods?' Wait for their answer. ONLY THEN call this function
35674
+ * with the product name they give you. Calling without a product query will fail.
35675
+ */
35676
+ search(query: string): Promise<SearchResults>;
35677
+ }
35678
+ }
35679
+
34711
35680
  declare namespace BowmarkProvider_winestyles {
34712
35681
  // ── WineStyles — the unit's own declarations, verbatim ──
34713
35682
  interface WinestylesStore {
@@ -35055,6 +36024,13 @@ interface YoutubeVideo {
35055
36024
  thumbnails: { url: string; width: number; height: number }[];
35056
36025
  }
35057
36026
 
36027
+ interface YoutubeCaptionTrack {
36028
+ languageCode: string; // e.g. "en", "de-DE", "pt-BR"
36029
+ name: string; // the site's own display name, e.g. "English (auto-generated)"
36030
+ isAutoGenerated: boolean; // true for a track YouTube generated itself, false for a human/uploader one
36031
+ isDefault: boolean; // true for the track getTranscript reads by default
36032
+ }
36033
+
35058
36034
  interface YoutubeComment {
35059
36035
  commentId: string;
35060
36036
  author: string;
@@ -35065,6 +36041,7 @@ interface YoutubeComment {
35065
36041
  replyCount: number;
35066
36042
  isPinned: boolean;
35067
36043
  isHeartedByCreator: boolean;
36044
+ repliesContinuation: string | null; // pass to listCommentReplies as { continuation }; null when replyCount is 0
35068
36045
  }
35069
36046
 
35070
36047
  interface YoutubeCommentPage {
@@ -35072,6 +36049,250 @@ interface YoutubeCommentPage {
35072
36049
  continuation: string | null; // pass back as { continuation } for the next page; null on the last
35073
36050
  }
35074
36051
 
36052
+ interface YoutubeCommentReply {
36053
+ commentId: string;
36054
+ author: string;
36055
+ authorChannelId: string | null;
36056
+ text: string;
36057
+ likeCount: string; // same convention as YoutubeComment.likeCount
36058
+ publishedTime: string; // YouTube's own relative phrase, e.g. "1 year ago"
36059
+ isHeartedByCreator: boolean;
36060
+ }
36061
+
36062
+ interface YoutubeCommentReplyPage {
36063
+ replies: YoutubeCommentReply[];
36064
+ continuation: string | null; // pass back as { continuation } for the next page; null on the last
36065
+ }
36066
+
36067
+ interface YoutubeChannelLink {
36068
+ title: string;
36069
+ url: string; // the real destination, decoded off YouTube's own redirect wrapper
36070
+ }
36071
+
36072
+ interface YoutubeChannel {
36073
+ channelId: string;
36074
+ handle: string | null; // null for a legacy /c/ or /user/ vanity URL with no @handle
36075
+ title: string;
36076
+ description: string;
36077
+ subscriberCountText: string | null; // YouTube's own abbreviated text, e.g. "517M subscribers"
36078
+ videoCount: number | null;
36079
+ viewCount: number | null;
36080
+ country: string | null;
36081
+ joinedDate: string | null; // ISO 8601 date
36082
+ links: YoutubeChannelLink[];
36083
+ avatar: string | null;
36084
+ banner: string | null;
36085
+ }
36086
+
36087
+ interface YoutubeChannelVideo {
36088
+ videoId: string;
36089
+ url: string;
36090
+ title: string;
36091
+ views: string | null; // YouTube's own abbreviated text, e.g. "101M views"
36092
+ published: string | null; // YouTube's own phrase, e.g. "11 days ago"
36093
+ publishedAgeSeconds: number | null;
36094
+ length: string | null; // e.g. "23:28"; null for a live stream
36095
+ thumbnail: string | null;
36096
+ }
36097
+
36098
+ interface YoutubeChannelVideoPage {
36099
+ videos: YoutubeChannelVideo[];
36100
+ continuation: string | null; // pass back as { continuation } for the next page; null on the last
36101
+ }
36102
+
36103
+ interface YoutubeChannelShort {
36104
+ videoId: string;
36105
+ url: string; // https://www.youtube.com/shorts/<id> — a Short has no watch?v= URL
36106
+ title: string;
36107
+ views: string | null; // YouTube's own abbreviated text WITH "views" already in it, e.g. "13M views"
36108
+ thumbnail: string | null;
36109
+ // no publish date, no length — neither exists anywhere in the Shorts-tab shape
36110
+ }
36111
+
36112
+ interface YoutubeChannelShortPage {
36113
+ shorts: YoutubeChannelShort[];
36114
+ continuation: string | null; // pass back as { continuation } for the next page; null on the last
36115
+ }
36116
+
36117
+ type YoutubeChannelLiveStreamStatus = "upcoming" | "live" | "ended";
36118
+
36119
+ interface YoutubeChannelLiveStream {
36120
+ videoId: string;
36121
+ url: string;
36122
+ title: string;
36123
+ status: YoutubeChannelLiveStreamStatus;
36124
+ watching: string | null; // "N watching" (live) or "N waiting" (upcoming); null once ended
36125
+ views: string | null; // YouTube's own abbreviated text, e.g. "94K views" — ended only
36126
+ scheduledFor: string | null; // e.g. "Scheduled for 9/19/26, 6:00 AM" — upcoming only
36127
+ published: string | null; // e.g. "Streamed 1 day ago" — ended only
36128
+ publishedAgeSeconds: number | null;
36129
+ length: string | null; // e.g. "9:05:30" — ended only
36130
+ thumbnail: string | null;
36131
+ }
36132
+
36133
+ interface YoutubeChannelLiveStreamPage {
36134
+ streams: YoutubeChannelLiveStream[];
36135
+ continuation: string | null; // pass back as { continuation } for the next page; null on the last
36136
+ }
36137
+
36138
+ interface YoutubeChannelPlaylist {
36139
+ playlistId: string;
36140
+ url: string;
36141
+ title: string;
36142
+ count: string | null; // YouTube's own badge text, e.g. "197 videos" or "20 episodes" for a podcast
36143
+ updated: string | null; // e.g. "today", "5 days ago" — null when the row carries no update stat
36144
+ thumbnail: string | null;
36145
+ }
36146
+
36147
+ interface YoutubeChannelPlaylistPage {
36148
+ playlists: YoutubeChannelPlaylist[];
36149
+ continuation: string | null; // pass back as { continuation } for the next page; null on the last
36150
+ }
36151
+
36152
+ interface YoutubeChannelPostImage {
36153
+ kind: "image";
36154
+ images: string[]; // one or several, largest available URL each
36155
+ }
36156
+
36157
+ interface YoutubeChannelPostPoll {
36158
+ kind: "poll";
36159
+ choices: string[]; // choice text only — vote counts are hidden from a logged-out viewer
36160
+ }
36161
+
36162
+ interface YoutubeChannelPostVideo {
36163
+ kind: "video"; // a video the channel shared into this tab — may belong to another channel
36164
+ videoId: string;
36165
+ title: string | null;
36166
+ }
36167
+
36168
+ type YoutubeChannelPostAttachment =
36169
+ | YoutubeChannelPostImage
36170
+ | YoutubeChannelPostPoll
36171
+ | YoutubeChannelPostVideo
36172
+ | null;
36173
+
36174
+ interface YoutubeChannelPost {
36175
+ postId: string;
36176
+ url: string;
36177
+ author: string | null;
36178
+ text: string | null;
36179
+ published: string | null; // YouTube's own phrase, e.g. "2 weeks ago", "(edited)" appended on an edited post
36180
+ publishedAgeSeconds: number | null;
36181
+ likeCount: string | null; // YouTube's own abbreviated text, e.g. "407K" — no "likes"
36182
+ commentCount: string | null; // YouTube's own abbreviated text, e.g. "6.7K" — no "comments"
36183
+ attachment: YoutubeChannelPostAttachment;
36184
+ }
36185
+
36186
+ interface YoutubeChannelPostPage {
36187
+ posts: YoutubeChannelPost[];
36188
+ continuation: string | null; // pass back as { continuation } for the next page; null on the last
36189
+ }
36190
+
36191
+ interface YoutubeChannelSearchPage {
36192
+ videos: YoutubeSearchVideo[];
36193
+ continuation: string | null; // pass back as { continuation } for the next page; null on the last
36194
+ }
36195
+
36196
+ interface YoutubeRelatedVideo {
36197
+ videoId: string;
36198
+ url: string;
36199
+ title: string;
36200
+ channel: string | null;
36201
+ channelId: string | null;
36202
+ views: string | null; // YouTube's own abbreviated text, e.g. "206M" — the bare number, not "206M views"
36203
+ published: string | null; // YouTube's own phrase, e.g. "16y ago"
36204
+ publishedAgeSeconds: number | null;
36205
+ length: string | null; // e.g. "3:24"; null for a live stream
36206
+ thumbnail: string | null;
36207
+ }
36208
+
36209
+ interface YoutubeRelatedVideoPage {
36210
+ videos: YoutubeRelatedVideo[];
36211
+ continuation: string | null; // pass back as { continuation } for the next page; null on the last
36212
+ }
36213
+
36214
+ interface YoutubeChapter {
36215
+ title: string;
36216
+ startSeconds: number; // pass to watch?v=<id>&t=<startSeconds>s
36217
+ timeDescription: string; // YouTube's own display text, e.g. "1:03:10"
36218
+ }
36219
+
36220
+ interface YoutubeLiveChatMessage {
36221
+ authorName: string;
36222
+ authorChannelId: string | null;
36223
+ text: string;
36224
+ timestampUsec: string; // YouTube's own microsecond epoch timestamp, as a string
36225
+ }
36226
+
36227
+ interface YoutubeLiveChat {
36228
+ open: boolean; // false when there is no chat to read at all — see notice
36229
+ notice: string | null; // the site's own sentence when open is false
36230
+ messages: YoutubeLiveChatMessage[];
36231
+ continuation: string | null; // pass back as { continuation } for the next batch; null once the chat has ended
36232
+ }
36233
+
36234
+ interface YoutubePlaylist {
36235
+ playlistId: string;
36236
+ title: string;
36237
+ description: string; // "" when the playlist has none (e.g. a channel's auto Uploads playlist)
36238
+ channelId: string | null;
36239
+ channelTitle: string | null;
36240
+ videoCount: number | null;
36241
+ viewCount: number | null;
36242
+ lastUpdated: string | null; // YouTube's own text: an absolute date, or "N days ago" on an Uploads playlist
36243
+ thumbnail: string | null;
36244
+ }
36245
+
36246
+ interface YoutubePlaylistVideo {
36247
+ videoId: string;
36248
+ url: string;
36249
+ title: string;
36250
+ channelId: string | null; // the PUBLISHING channel, which can differ from the playlist owner
36251
+ channelTitle: string | null;
36252
+ views: string | null; // YouTube's own abbreviated text, e.g. "4.9M views"
36253
+ published: string | null; // YouTube's own phrase, e.g. "5 years ago"
36254
+ publishedAgeSeconds: number | null;
36255
+ length: string | null; // e.g. "1:00:02"; null for a live stream
36256
+ thumbnail: string | null;
36257
+ }
36258
+
36259
+ interface YoutubeCreatedChannel {
36260
+ channelId: string;
36261
+ name: string; // the account's own Google profile name
36262
+ url: string;
36263
+ alreadyExisted: boolean; // true when the account already had one; nothing was created
36264
+ }
36265
+
36266
+ interface YoutubeCreatedPlaylist {
36267
+ playlistId: string;
36268
+ title: string;
36269
+ privacy: "private" | "unlisted" | "public";
36270
+ url: string; // open this to see it
36271
+ }
36272
+
36273
+ interface YoutubePlaylistEdit {
36274
+ playlistId: string;
36275
+ added: string[]; // what was sent and accepted, in order — not a per-video receipt
36276
+ url: string;
36277
+ }
36278
+
36279
+ interface YoutubePlaylistVideoPage {
36280
+ videos: YoutubePlaylistVideo[];
36281
+ continuation: string | null; // pass back as { continuation } for the next page; null on the last
36282
+ }
36283
+
36284
+ interface YoutubeStreamFormat {
36285
+ itag: number;
36286
+ mimeType: string;
36287
+ bitrate: number;
36288
+ width: number | null;
36289
+ height: number | null;
36290
+ fps: number | null;
36291
+ qualityLabel: string | null;
36292
+ contentLength: string | null; // null on the muxed entry — YouTube does not publish it there
36293
+ approxDurationMs: string | null;
36294
+ }
36295
+
35075
36296
  /**
35076
36297
  * A YouTube video's own caption transcript, read off the site's own Transcript panel —
35077
36298
  * timestamped lines plus the full text as one string. Language selection is not offered yet;
@@ -35087,6 +36308,14 @@ interface YoutubeCommentPage {
35087
36308
  */
35088
36309
  search(input: { query: string; uploadedWithin?: "today" | "week" | "month" | "year" }): Promise<YoutubeSearchVideo[]>;
35089
36310
 
36311
+ /**
36312
+ * YouTube's own autocomplete for a partial query — the dropdown it shows while somebody is
36313
+ * still typing, in the site's own ranked order. Use it to turn a vague phrase into the wording
36314
+ * YouTube actually indexes before spending a call on `search`. A query matching nothing
36315
+ * returns a real, honest empty array rather than throwing.
36316
+ */
36317
+ suggestSearches(input: { query: string }): Promise<string[]>;
36318
+
35090
36319
  /**
35091
36320
  * Returns a YouTube video's own caption transcript. `video` is a bare 11-character video id or
35092
36321
  * any watch/shorts/embed/live/youtu.be URL. `segments` is [] — a real, honest answer — when
@@ -35123,6 +36352,234 @@ interface YoutubeCommentPage {
35123
36352
  * there are no more pages.
35124
36353
  */
35125
36354
  listComments(input: { video: string; sortBy?: "top" | "newest" } | { continuation: string }): Promise<YoutubeCommentPage>;
36355
+
36356
+ /**
36357
+ * The replies under one comment thread, which YouTube hides behind a "N replies" button and
36358
+ * never ships with the thread itself. `continuation` is a thread's own `repliesContinuation`
36359
+ * off a `listComments` row (null when it has no replies) for the first page, or this
36360
+ * function's own returned `continuation` for the next one; it is null once there are no more
36361
+ * pages. Each reply carries its author, text, like count and whether the creator hearted it —
36362
+ * no reply count or pinned flag, since a reply cannot itself be a thread or be pinned.
36363
+ */
36364
+ listCommentReplies(input: { continuation: string }): Promise<YoutubeCommentReplyPage>;
36365
+
36366
+ /**
36367
+ * The videos YouTube itself puts next to this one — the "up next" rail — each with its id,
36368
+ * title, channel, YouTube's own abbreviated view-count text (e.g. "206M", without the word
36369
+ * "views"), upload age, length and thumbnail. `video` is a bare 11-character video id or any
36370
+ * watch/shorts/embed/live/youtu.be URL, exactly as `getTranscript` takes it. Pass back
36371
+ * `continuation` alone — no `video` needed — to read the next page; it is null once YouTube
36372
+ * offers no further "Show more", which some videos never do even on page 1.
36373
+ */
36374
+ listRelatedVideos(input: { video: string } | { continuation: string }): Promise<YoutubeRelatedVideoPage>;
36375
+
36376
+ /**
36377
+ * A video's own chapter markers — the labelled sections YouTube shows on the scrub bar — each
36378
+ * with its title, start time in seconds and YouTube's own display text for that time (e.g.
36379
+ * "1:03:10"). `video` is a bare 11-character video id or any watch/shorts/embed/live/youtu.be
36380
+ * URL, exactly as `getTranscript` takes it. `[]` when the video has no chapters at all — a
36381
+ * real, honest answer, not a failure.
36382
+ */
36383
+ listChapters(input: { video: string }): Promise<YoutubeChapter[]>;
36384
+
36385
+ /**
36386
+ * The messages scrolling past a live stream right now — each with its author, text and
36387
+ * YouTube's own microsecond timestamp. `video` is a bare 11-character video id or any
36388
+ * watch/shorts/embed/live/youtu.be URL, exactly as `getTranscript` takes it, for the FIRST
36389
+ * call; pass back `continuation` alone — no `video` needed — to read what arrived since.
36390
+ * `open` is false, with the site's own `notice` sentence (e.g. "Chat is disabled for this live
36391
+ * stream."), when the stream has never gone live, its chat is off, or it already ended —
36392
+ * nothing in the response tells those three apart. `continuation` is null once the stream
36393
+ * stops offering one.
36394
+ */
36395
+ getLiveChat(input: { video: string } | { continuation: string }): Promise<YoutubeLiveChat>;
36396
+
36397
+ /**
36398
+ * Which languages a video's captions are available in, whether each was written by a
36399
+ * human/uploader or generated by YouTube itself, and which one `getTranscript` reads by
36400
+ * default. `video` is a bare 11-character video id or any watch/shorts/embed/live/youtu.be
36401
+ * URL, exactly as `getTranscript` takes it. `[]` when the video has no captions at all — a
36402
+ * real, honest answer, not a failure. Does not itself return caption text or a language choice
36403
+ * for `getTranscript`, which today always reads the default track.
36404
+ */
36405
+ listCaptionTracks(input: { video: string }): Promise<YoutubeCaptionTrack[]>;
36406
+
36407
+ /**
36408
+ * The renditions a video is actually available in — resolution, frame rate, codec, bitrate,
36409
+ * approximate file size and duration for each video and audio stream YouTube holds. Answers
36410
+ * "is this available in 4K" and "how big is it". It returns the CATALOGUE of formats, not a
36411
+ * playable or downloadable link: see the manifest note on why playable URLs are a separate
36412
+ * (rung 14) problem.
36413
+ */
36414
+ listStreamFormats(input: { video: string }): Promise<YoutubeStreamFormat[]>;
36415
+
36416
+ /**
36417
+ * The videos on one of YouTube's own hashtag pages (`youtube.com/hashtag/<tag>`) — a topic
36418
+ * feed reachable from a bare word, with no channel and no search ranking in the way. Same row
36419
+ * shape `search` returns. `hashtag` is the bare tag, with or without a leading "#". This is a
36420
+ * curated, CAPPED feed rather than a paged one — no tag measured carries a "show more", so
36421
+ * `[]` back means the site had nothing to show ("Not much to see right now"), not that the
36422
+ * call failed.
36423
+ */
36424
+ listHashtagVideos(input: { hashtag: string }): Promise<YoutubeSearchVideo[]>;
36425
+
36426
+ /**
36427
+ * A channel's own page as facts: display name, @handle, an abbreviated subscriber count text
36428
+ * (YouTube never publishes an exact one), the About tab's full description, total video count,
36429
+ * lifetime view count, country, the ISO date it joined, the links it lists (resolved to their
36430
+ * real destination, not YouTube's redirect wrapper), and its avatar and banner images.
36431
+ * `channel` is a channel id (`UC…`), an `@handle`, or a channel URL — not a plain name, which
36432
+ * `findChannel` resolves to an id first. Every field past `channelId`/`handle`/`title` comes
36433
+ * off the About panel; on the rare response that carries no panel at all they come back
36434
+ * null/empty rather than throwing.
36435
+ */
36436
+ getChannel(input: { channel: string }): Promise<YoutubeChannel>;
36437
+
36438
+ /**
36439
+ * What a channel has published, newest first and paged — each video's id, url, title,
36440
+ * YouTube's own abbreviated view-count text (e.g. "101M views"), upload age, length and
36441
+ * thumbnail. `channel` takes a channel id, an @handle, or a channel URL, exactly as
36442
+ * `getChannel` does — not a plain name, which `findChannel` resolves first. Pass back
36443
+ * `continuation` alone — no `channel` needed — to read the next page; it is null once there
36444
+ * are no more pages.
36445
+ */
36446
+ listChannelVideos(input: { channel: string } | { continuation: string }): Promise<YoutubeChannelVideoPage>;
36447
+
36448
+ /**
36449
+ * What a channel has published to its Shorts tab, in the site's own order and paged — each
36450
+ * short's id, its `/shorts/<id>` url, title, and YouTube's own abbreviated view-count text
36451
+ * (e.g. "13M views"). `channel` takes a channel id, an @handle, or a channel URL, exactly as
36452
+ * `listChannelVideos` does. A Short's own page carries no publish date and no length anywhere
36453
+ * in the site's data — YouTube does not publish either for this tab, so neither field exists
36454
+ * on the row. Pass back `continuation` alone — no `channel` needed — to read the next page; it
36455
+ * is null once there are no more pages.
36456
+ */
36457
+ listChannelShorts(input: { channel: string } | { continuation: string }): Promise<YoutubeChannelShortPage>;
36458
+
36459
+ /**
36460
+ * A channel's Live tab, paged — upcoming, in-progress and past broadcasts, in the site's own
36461
+ * order. Each row carries `status` (`"upcoming" | "live" | "ended"`): upcoming carries
36462
+ * `watching` as a waiting-room count and `scheduledFor`; live carries `watching` as a
36463
+ * concurrent viewer count; ended carries `views`, `published` ("Streamed 1 day ago") and
36464
+ * `length`, the same fields `listChannelVideos` returns. `channel` takes a channel id, an
36465
+ * @handle, or a channel URL, exactly as `listChannelVideos` does. A channel that has never
36466
+ * streamed carries no Live tab at all — YouTube answers with its Home tab instead — which
36467
+ * reads back as `{ streams: [], continuation: null }`, the same empty page a channel with a
36468
+ * Live tab and zero streams on it would return. Pass back `continuation` alone — no `channel`
36469
+ * needed — to read the next page; it is null once there are no more pages.
36470
+ */
36471
+ listChannelLiveStreams(input: { channel: string } | { continuation: string }): Promise<YoutubeChannelLiveStreamPage>;
36472
+
36473
+ /**
36474
+ * The playlists a channel has published, in the site's own order and paged — each one's id,
36475
+ * its `/playlist?list=<id>` url, title, YouTube's own badge text ("197 videos", or "20
36476
+ * episodes" for a podcast the channel runs, which lives on this same tab), and its "Updated …"
36477
+ * stat with the prefix stripped ("today", "5 days ago") — null when a playlist carries no
36478
+ * update stat at all. `channel` takes a channel id, an @handle, or a channel URL, exactly as
36479
+ * `listChannelVideos` does. The door from a channel to `getPlaylist` and `listPlaylistVideos`.
36480
+ * Pass back `continuation` alone — no `channel` needed — to read the next page; it is null
36481
+ * once there are no more pages.
36482
+ */
36483
+ listChannelPlaylists(input: { channel: string } | { continuation: string }): Promise<YoutubeChannelPlaylistPage>;
36484
+
36485
+ /**
36486
+ * A channel's Community tab — the text, image and poll posts a creator writes between uploads,
36487
+ * never appearing on any video tab. Each post carries its author, plain text, YouTube's own
36488
+ * relative age ("2 weeks ago", "(edited)" appended on an edited post), abbreviated like and
36489
+ * comment counts ("407K", "6.7K", without the words), and an `attachment` of one of three
36490
+ * kinds — `{ kind: "image", images }` (one or several), `{ kind: "poll", choices }` (choice
36491
+ * text only, no vote counts — hidden from a logged-out viewer), `{ kind: "video", videoId,
36492
+ * title }` (a video the channel shared into the tab, which can belong to another channel
36493
+ * entirely) — or `null` for a text-only post. `channel` takes a channel id, an @handle, or a
36494
+ * channel URL, exactly as `listChannelVideos` does. Pass back `continuation` alone — no
36495
+ * `channel` needed — to read the next page; it is null once there are no more pages.
36496
+ */
36497
+ listChannelPosts(input: { channel: string } | { continuation: string }): Promise<YoutubeChannelPostPage>;
36498
+
36499
+ /**
36500
+ * Search one channel's own videos rather than the whole site — the search box on a channel
36501
+ * page. Returns the same video rows `search` does (id, url, title, channel, upload age,
36502
+ * length, views), scoped to that channel and paged. `channel` takes a channel id, an @handle,
36503
+ * or a channel URL, exactly as `listChannelVideos` does. A channel with no match at all
36504
+ * answers a real, honest empty page rather than throwing. Pass back `continuation` alone — no
36505
+ * `channel`/`query` needed — to read the next page; it is null once there are no more pages.
36506
+ */
36507
+ searchWithinChannel(input: { channel: string; query: string } | { continuation: string }): Promise<YoutubeChannelSearchPage>;
36508
+
36509
+ /**
36510
+ * A playlist's own facts: title, description, the channel that owns it, exact video and view
36511
+ * counts, and when it was last updated (an absolute date on an ordinary playlist, YouTube's
36512
+ * own relative phrase like "5 days ago" on a channel's auto-generated Uploads playlist).
36513
+ * `playlist` is a playlist id or any playlist/watch URL carrying a `list` param — including a
36514
+ * channel's Uploads playlist, whose id is always `"UU" + channelId.slice(2)`.
36515
+ */
36516
+ getPlaylist(input: { playlist: string }): Promise<YoutubePlaylist>;
36517
+
36518
+ /**
36519
+ * The videos inside a playlist, in the playlist's own order and paged — each video's id, url,
36520
+ * title, the channel that PUBLISHED it (not necessarily the playlist owner), YouTube's own
36521
+ * abbreviated view-count text, upload age, length and thumbnail. `playlist` takes the same id
36522
+ * or URL `getPlaylist` does, including a channel's Uploads playlist (`"UU" +
36523
+ * channelId.slice(2)`). Pass back `continuation` alone — no `playlist` needed — to read the
36524
+ * next page; it is null once there are no more pages.
36525
+ */
36526
+ listPlaylistVideos(input: { playlist: string } | { continuation: string }): Promise<YoutubePlaylistVideoPage>;
36527
+
36528
+ /**
36529
+ * The videos on the signed-in account's own YouTube home page — the personalized
36530
+ * recommendation grid, in YouTube's own order, which is what that account actually sees on
36531
+ * youtube.com right now. NEEDS A SIGN-IN and exists nowhere else: it is not in the public Data
36532
+ * API, and logged out the same request answers 200 with an EMPTY grid rather than an error.
36533
+ * Call `bowmark.video_library.homeFeed` rather than this directly.
36534
+ */
36535
+ listHomeFeed(input?: { limit?: number }): Promise<YoutubeSearchVideo[]>;
36536
+
36537
+ /**
36538
+ * The signed-in account's Watch Later queue, newest first, paged like any playlist. NEEDS A
36539
+ * SIGN-IN, and a grant is issued to a capability — call `bowmark.video_library.watchLater`
36540
+ * rather than this directly. Not reachable through YouTube's public Data API at all: Google
36541
+ * removed access to the `WL` list in 2016.
36542
+ */
36543
+ listWatchLater(input?: { continuation?: string }): Promise<YoutubePlaylistVideoPage>;
36544
+
36545
+ /**
36546
+ * The videos the signed-in account has liked, newest first, paged like any playlist. NEEDS A
36547
+ * SIGN-IN — call `bowmark.video_library.liked` rather than this directly.
36548
+ */
36549
+ listLikedVideos(input?: { continuation?: string }): Promise<YoutubePlaylistVideoPage>;
36550
+
36551
+ /**
36552
+ * Creates an EMPTY playlist on the signed-in account and returns its id and URL. `privacy`
36553
+ * defaults to "private". NOT idempotent — YouTube allows duplicate titles, so calling twice
36554
+ * makes two playlists. Title it for the PERSON whose account it lands on: the subject in their
36555
+ * own words, never a tool name, run id or timestamp, and set `description` to what the videos
36556
+ * have in common. NEEDS A SIGN-IN — call `bowmark.video_library.createPlaylist` rather than
36557
+ * this directly.
36558
+ */
36559
+ createPlaylist(input: { title: string; description?: string; privacy?: "private" | "unlisted" | "public" }): Promise<YoutubeCreatedPlaylist>;
36560
+
36561
+ /**
36562
+ * Creates the signed-in Google account's YouTube CHANNEL, using the account's own name and
36563
+ * profile photo — the only thing YouTube's own dialog offers on this path. Most Google
36564
+ * accounts have never had one, and without one YouTube refuses to make a public or unlisted
36565
+ * playlist (a private one works, because that belongs to the account rather than to a
36566
+ * channel). THIS ACCEPTS YOUTUBE'S TERMS OF SERVICE on the account holder's behalf, which is
36567
+ * what their own Create channel button does, so do not call it to work around an error — call
36568
+ * it because the person whose account it is asked for a channel. Idempotent: an account that
36569
+ * already has one gets `alreadyExisted: true` and nothing is created. NEEDS A SIGN-IN.
36570
+ */
36571
+ createChannel(): Promise<YoutubeCreatedChannel>;
36572
+
36573
+ /**
36574
+ * Adds one or many videos to one of the signed-in account's own playlists, as a SINGLE edit
36575
+ * rather than one request per video. Order is preserved: the videos appear in the order they
36576
+ * were sent, measured 2026-09-18. A playlist READ BACK IN THE SAME RUN can still come back
36577
+ * empty — the write is applied but YouTube indexes it a beat later, measured at ~2s — so do
36578
+ * not treat an immediate empty read as a failed add. YouTube permits duplicates, so adding a
36579
+ * video already present adds it again. NEEDS A SIGN-IN — call
36580
+ * `bowmark.video_library.addToPlaylist` rather than this directly.
36581
+ */
36582
+ addToPlaylist(input: { playlist: string; video?: string; videos?: string[] }): Promise<YoutubePlaylistEdit>;
35126
36583
  }
35127
36584
  }
35128
36585
 
@@ -36026,6 +37483,7 @@ interface BowmarkProviders {
36026
37483
  acqualinaresort: BowmarkProvider_acqualinaresort.Unit;
36027
37484
  ai_engineer: BowmarkProvider_ai_engineer.Unit;
36028
37485
  aiper: BowmarkProvider_aiper.Unit;
37486
+ airtable: BowmarkProvider_airtable.Unit;
36029
37487
  ajmadison: BowmarkProvider_ajmadison.Unit;
36030
37488
  allied: BowmarkProvider_allied.Unit;
36031
37489
  alphavantage: BowmarkProvider_alphavantage.Unit;
@@ -36060,6 +37518,7 @@ interface BowmarkProviders {
36060
37518
  ayreshotels: BowmarkProvider_ayreshotels.Unit;
36061
37519
  azazie: BowmarkProvider_azazie.Unit;
36062
37520
  azure: BowmarkProvider_azure.Unit;
37521
+ bahn: BowmarkProvider_bahn.Unit;
36063
37522
  bankmycell: BowmarkProvider_bankmycell.Unit;
36064
37523
  barletta: BowmarkProvider_barletta.Unit;
36065
37524
  barnesfoundation: BowmarkProvider_barnesfoundation.Unit;
@@ -36140,6 +37599,7 @@ interface BowmarkProviders {
36140
37599
  completehomewarranty_com: BowmarkProvider_completehomewarranty_com.Unit;
36141
37600
  consultnet: BowmarkProvider_consultnet.Unit;
36142
37601
  costco: BowmarkProvider_costco.Unit;
37602
+ countycourt_vic_gov_au: BowmarkProvider_countycourt_vic_gov_au.Unit;
36143
37603
  couponfollow: BowmarkProvider_couponfollow.Unit;
36144
37604
  credibly_com: BowmarkProvider_credibly_com.Unit;
36145
37605
  cruiselakegeneva: BowmarkProvider_cruiselakegeneva.Unit;
@@ -36157,7 +37617,9 @@ interface BowmarkProviders {
36157
37617
  deltadentalma: BowmarkProvider_deltadentalma.Unit;
36158
37618
  dentalplans: BowmarkProvider_dentalplans.Unit;
36159
37619
  detailxperts: BowmarkProvider_detailxperts.Unit;
37620
+ deutschepost: BowmarkProvider_deutschepost.Unit;
36160
37621
  developersopenai: BowmarkProvider_developersopenai.Unit;
37622
+ dfs_rotogrinderssearch: BowmarkProvider_dfs_rotogrinderssearch.Unit;
36161
37623
  dice: BowmarkProvider_dice.Unit;
36162
37624
  dickssportinggoods: BowmarkProvider_dickssportinggoods.Unit;
36163
37625
  dillards: BowmarkProvider_dillards.Unit;
@@ -36170,11 +37632,13 @@ interface BowmarkProviders {
36170
37632
  elase: BowmarkProvider_elase.Unit;
36171
37633
  elevenlabs: BowmarkProvider_elevenlabs.Unit;
36172
37634
  embroker: BowmarkProvider_embroker.Unit;
37635
+ energyaustralia_com_au: BowmarkProvider_energyaustralia_com_au.Unit;
36173
37636
  epromos: BowmarkProvider_epromos.Unit;
36174
37637
  eq3: BowmarkProvider_eq3.Unit;
36175
37638
  equinox_hotels: BowmarkProvider_equinox_hotels.Unit;
36176
37639
  erieinsurance: BowmarkProvider_erieinsurance.Unit;
36177
37640
  etsy: BowmarkProvider_etsy.Unit;
37641
+ evag: BowmarkProvider_evag.Unit;
36178
37642
  eventsource: BowmarkProvider_eventsource.Unit;
36179
37643
  evolutionofsmooth: BowmarkProvider_evolutionofsmooth.Unit;
36180
37644
  evolvemedspa: BowmarkProvider_evolvemedspa.Unit;
@@ -36273,6 +37737,7 @@ interface BowmarkProviders {
36273
37737
  landmarkhw_com: BowmarkProvider_landmarkhw_com.Unit;
36274
37738
  lasikplus: BowmarkProvider_lasikplus.Unit;
36275
37739
  legacyhomesal: BowmarkProvider_legacyhomesal.Unit;
37740
+ letterboxd: BowmarkProvider_letterboxd.Unit;
36276
37741
  linkedin: BowmarkProvider_linkedin.Unit;
36277
37742
  liquiddeath: BowmarkProvider_liquiddeath.Unit;
36278
37743
  liquidspace: BowmarkProvider_liquidspace.Unit;
@@ -36320,23 +37785,29 @@ interface BowmarkProviders {
36320
37785
  oanda: BowmarkProvider_oanda.Unit;
36321
37786
  oliverwinery: BowmarkProvider_oliverwinery.Unit;
36322
37787
  onthemarket: BowmarkProvider_onthemarket.Unit;
37788
+ originenergy_com_au: BowmarkProvider_originenergy_com_au.Unit;
36323
37789
  othership: BowmarkProvider_othership.Unit;
36324
37790
  otto: BowmarkProvider_otto.Unit;
36325
37791
  outdoorresearch: BowmarkProvider_outdoorresearch.Unit;
36326
37792
  pacificabeauty: BowmarkProvider_pacificabeauty.Unit;
36327
37793
  pacificcompanies: BowmarkProvider_pacificcompanies.Unit;
36328
37794
  pacificlifestylehomes: BowmarkProvider_pacificlifestylehomes.Unit;
37795
+ packlane: BowmarkProvider_packlane.Unit;
37796
+ pawsup: BowmarkProvider_pawsup.Unit;
36329
37797
  paypal: BowmarkProvider_paypal.Unit;
36330
37798
  perennialsandsutherland: BowmarkProvider_perennialsandsutherland.Unit;
36331
37799
  pilotprotocol: BowmarkProvider_pilotprotocol.Unit;
36332
37800
  pirateship: BowmarkProvider_pirateship.Unit;
36333
37801
  pizzahut: BowmarkProvider_pizzahut.Unit;
37802
+ planning_inspectorate_ni: BowmarkProvider_planning_inspectorate_ni.Unit;
36334
37803
  platform_claude_com: BowmarkProvider_platform_claude_com.Unit;
36335
37804
  polymarket: BowmarkProvider_polymarket.Unit;
36336
37805
  polytex: BowmarkProvider_polytex.Unit;
36337
37806
  poshmark: BowmarkProvider_poshmark.Unit;
36338
37807
  positivegrid: BowmarkProvider_positivegrid.Unit;
37808
+ postcard_direct_mail: BowmarkProvider_postcard_direct_mail.Unit;
36339
37809
  postiz: BowmarkProvider_postiz.Unit;
37810
+ powys: BowmarkProvider_powys.Unit;
36340
37811
  premierbuildings: BowmarkProvider_premierbuildings.Unit;
36341
37812
  prime_video: BowmarkProvider_prime_video.Unit;
36342
37813
  progressive: BowmarkProvider_progressive.Unit;
@@ -36427,6 +37898,7 @@ interface BowmarkProviders {
36427
37898
  waterfurnace: BowmarkProvider_waterfurnace.Unit;
36428
37899
  wearehirschfeld: BowmarkProvider_wearehirschfeld.Unit;
36429
37900
  wellfound: BowmarkProvider_wellfound.Unit;
37901
+ wholefoodsmarket: BowmarkProvider_wholefoodsmarket.Unit;
36430
37902
  winestyles: BowmarkProvider_winestyles.Unit;
36431
37903
  xpresswellnessurgentcare: BowmarkProvider_xpresswellnessurgentcare.Unit;
36432
37904
  ycombinator: BowmarkProvider_ycombinator.Unit;
@@ -88166,9 +89638,11 @@ interface BowmarkLibrary {
88166
89638
  costume_size_check: BowmarkCapability_costume_size_check.Unit;
88167
89639
  coworking: BowmarkCapability_coworking.Unit;
88168
89640
  currency_exchange: BowmarkCapability_currency_exchange.Unit;
89641
+ custom_packaging_quote: BowmarkCapability_custom_packaging_quote.Unit;
88169
89642
  custom_sofa_configurator: BowmarkCapability_custom_sofa_configurator.Unit;
88170
89643
  delivery: BowmarkCapability_delivery.Unit;
88171
89644
  developer_api_key_signup: BowmarkCapability_developer_api_key_signup.Unit;
89645
+ dfs_ownership_projections: BowmarkCapability_dfs_ownership_projections.Unit;
88172
89646
  domain: BowmarkCapability_domain.Unit;
88173
89647
  email: BowmarkCapability_email.Unit;
88174
89648
  entertainment_merch: BowmarkCapability_entertainment_merch.Unit;
@@ -88182,12 +89656,14 @@ interface BowmarkLibrary {
88182
89656
  istanbul_schedules: BowmarkCapability_istanbul_schedules.Unit;
88183
89657
  local_database_gui: BowmarkCapability_local_database_gui.Unit;
88184
89658
  local_html_preview: BowmarkCapability_local_html_preview.Unit;
89659
+ mac_trade_in: BowmarkCapability_mac_trade_in.Unit;
88185
89660
  mcp_registry: BowmarkCapability_mcp_registry.Unit;
88186
89661
  music: BowmarkCapability_music.Unit;
88187
89662
  pcparts: BowmarkCapability_pcparts.Unit;
88188
89663
  pet_boarding: BowmarkCapability_pet_boarding.Unit;
88189
89664
  phone_price: BowmarkCapability_phone_price.Unit;
88190
89665
  phone_trade_in: BowmarkCapability_phone_trade_in.Unit;
89666
+ postcard_direct_mail_quote: BowmarkCapability_postcard_direct_mail_quote.Unit;
88191
89667
  pricing: BowmarkCapability_pricing.Unit;
88192
89668
  products: BowmarkCapability_products.Unit;
88193
89669
  promocodes: BowmarkCapability_promocodes.Unit;
@@ -88205,6 +89681,7 @@ interface BowmarkLibrary {
88205
89681
  tariff: BowmarkCapability_tariff.Unit;
88206
89682
  text_to_speech: BowmarkCapability_text_to_speech.Unit;
88207
89683
  theme_park_tickets: BowmarkCapability_theme_park_tickets.Unit;
89684
+ video_library: BowmarkCapability_video_library.Unit;
88208
89685
  weather: BowmarkCapability_weather.Unit;
88209
89686
  web_form_fields: BowmarkCapability_web_form_fields.Unit;
88210
89687
  wireless: BowmarkCapability_wireless.Unit;