@burdenoff/website-sdk 2026.922.5 → 2026.923.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/explore.d.mts +4 -180
- package/dist/components/explore.d.ts +4 -180
- package/dist/components/explore.js +1458 -927
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +1225 -694
- package/dist/components/explore.mjs.map +1 -1
- package/dist/explore-D25zoXy9.d.mts +240 -0
- package/dist/explore-I4QnY4J9.d.ts +240 -0
- package/dist/{explore-types-DvQPiL1t.d.mts → explore-types-B5sdOC5M.d.mts} +75 -2
- package/dist/{explore-types-DvQPiL1t.d.ts → explore-types-B5sdOC5M.d.ts} +75 -2
- package/dist/hooks/index.d.mts +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +125 -8
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +125 -8
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +417 -25
- package/dist/index.d.ts +417 -25
- package/dist/index.js +2629 -872
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2610 -874
- package/dist/index.mjs.map +1 -1
- package/dist/{use-progressive-reveal-Ha3gYPfs.d.mts → use-progressive-reveal-Cmy8bA7L.d.mts} +54 -7
- package/dist/{use-progressive-reveal-BfU_IHip.d.ts → use-progressive-reveal-DHPGGxZu.d.ts} +54 -7
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -17,10 +17,12 @@ export { WebsiteSwitcher, WebsiteSwitcherProps } from './components/website-swit
|
|
|
17
17
|
export { LaunchCountdown, LaunchCountdownProps } from './components/launch-countdown.js';
|
|
18
18
|
export { ProblemSolved, ProblemsSolvedSection, ProblemsSolvedSectionProps } from './components/problems-solved.js';
|
|
19
19
|
export { DetectedPlatform, ElectronDownloadLink, ElectronDownloadLinkProps, detectElectronPlatform } from './components/electron-download.js';
|
|
20
|
-
|
|
20
|
+
import { Components } from 'react-markdown';
|
|
21
|
+
import { A as AnswerRendererStrings } from './explore-I4QnY4J9.js';
|
|
22
|
+
export { E as ExploreAnswerBody, a as ExploreAnswerBodyProps, b as ExploreAnswerStyles, c as ExplorePage, d as ExplorePageProps, e as answerPlainText, f as answerSpeechText, i as inlineImageOrigins, g as isInlineImageAllowed } from './explore-I4QnY4J9.js';
|
|
21
23
|
export { ExploreCta, ExploreCtaProps } from './components/explore-cta.js';
|
|
22
|
-
export { g as
|
|
23
|
-
export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions,
|
|
24
|
+
export { g as ESCALATE_EXPLORE_CONVERSATION_MUTATION, h as EXPLORE_CATALOG_QUERY, i as EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS, j as EXPLORE_ESCALATION_NOTE_SOFT_MAX, k as EXPLORE_MESSAGE_QUERY, l as EscalateExploreConversationInput, m as EscalateExploreConversationResult, c as ExploreCatalog, n as ExploreCatalogQueryData, o as ExploreConceptHighlight, p as ExploreConversation, q as ExploreCtaKind, r as ExploreCtaLink, s as ExploreErrorCode, t as ExploreEscalation, b as ExploreLimits, d as ExploreMessage, u as ExploreMessageQueryData, v as ExploreMessageRole, w as ExploreMessageStatus, E as ExploreProduct, a as ExploreReference, S as SEND_EXPLORE_MESSAGE_MUTATION, x as SendExploreMessageInput, y as SendExploreMessageMutationData, z as SendExploreMessageResult, A as looksLikeDeliverableEmail } from './explore-types-B5sdOC5M.js';
|
|
25
|
+
export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, c as ExploreEscalateOutcome, d as ExploreEscalateResult, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions, e as UseExploreChatResult, f as UseSpeechOutputOptions, g as UseSpeechOutputResult, h as classifyExploreError, s as stopSpeaking, u as useExploreChat, i as useProgressiveReveal, j as useSpeechOutput } from './use-progressive-reveal-DHPGGxZu.js';
|
|
24
26
|
export { RybbitAnalytics, RybbitAnalyticsProps } from './analytics/index.js';
|
|
25
27
|
export { PageHead, PageHeadProps } from './seo/index.js';
|
|
26
28
|
export { ProductData, ProductProvider, ProductProviderProps, useProduct, useProductConfig } from './product/index.js';
|
|
@@ -29,7 +31,6 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
29
31
|
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
30
32
|
export { B as BrowseStoreResult, G as GroupedStoreProducts, P as ProductCard, a as ProductCategory, R as RatingDistribution, S as SearchSuggestion, b as StarRating, c as StoreBrowsePage, d as StoreBrowsePageProps, e as StoreFacet, f as StoreFacets, g as StoreHomePage, h as StoreHomePageProps, i as StorePageProps, j as StoreProduct, k as StoreProductDetailPage, l as StoreProductDetailPageProps, m as StoreProductDetails, n as StorePublisher, o as StoreReview, p as StoreTerminology, q as StoreTypeFilter, T as TypeBadge, r as formatDownloads, s as formatPrice } from './product-card-CGxETsFa.js';
|
|
31
33
|
export { EXPLORE_RECAPTCHA_ACTION, RecaptchaV3, cn, getRecaptchaV3Token, loadRecaptchaV3 } from './utils/index.js';
|
|
32
|
-
import 'react-markdown';
|
|
33
34
|
import 'clsx';
|
|
34
35
|
|
|
35
36
|
interface CareersSubmissionFormProps {
|
|
@@ -197,31 +198,241 @@ declare function ConceptsPage({ productName, siteUrl, concepts, categories, cta,
|
|
|
197
198
|
*/
|
|
198
199
|
declare function ConceptDetailPage(props: ConceptDetailPageProps): react.JSX.Element;
|
|
199
200
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
201
|
+
/**
|
|
202
|
+
* Published answers — the shared data contract.
|
|
203
|
+
*
|
|
204
|
+
* ## Where the questions come from, and where they must NEVER come from
|
|
205
|
+
*
|
|
206
|
+
* Every product website publishes a set of question-and-answer pages built from a **curated
|
|
207
|
+
* question list**, answered by the live explore API against the baked corpus. The question
|
|
208
|
+
* list is written by us; the answer is the harness's own output for that question.
|
|
209
|
+
*
|
|
210
|
+
* They are **never** built from stored visitor conversations. `explore_messages` holds every
|
|
211
|
+
* question a real visitor has typed into `/explore`, and publishing those as indexed pages
|
|
212
|
+
* would be a privacy breach. That the rows carry no name does not save it: a question is not
|
|
213
|
+
* anonymous content. "Our farm outside Coimbatore has three staff and we are being billed X"
|
|
214
|
+
* identifies a business with nobody's name attached, and the person who typed it consented to
|
|
215
|
+
* being answered, not to being published. That table is an analytics and answer-quality input,
|
|
216
|
+
* which is what it was built for.
|
|
217
|
+
*
|
|
218
|
+
* So: nothing in this module, in `answers.tsx`, or in whatever generates a site's
|
|
219
|
+
* `src/data/answers.ts` may read `ExploreMessage`, `ExploreConversation` or `ExploreFeedback`
|
|
220
|
+
* rows. A {@link PublishedAnswer} has no conversation id, no message id, no visitor field and
|
|
221
|
+
* no free text that came from one — by construction, not by a denylist, because a denylist
|
|
222
|
+
* leaks the first column nobody thought of.
|
|
223
|
+
*
|
|
224
|
+
* ## The same care downstream
|
|
225
|
+
*
|
|
226
|
+
* A published answer must not contain anything that is not already public on our own
|
|
227
|
+
* websites. The harness only answers from the corpus, which is built from published pages, and
|
|
228
|
+
* every source here is a public URL — {@link isPublishedSourceUrl} is the page's own last
|
|
229
|
+
* check before it renders one as a link.
|
|
230
|
+
*
|
|
231
|
+
* ## Shape
|
|
232
|
+
*
|
|
233
|
+
* Each site ships a generated `src/data/answers.ts` exporting `ANSWERS`, `ANSWER_TOPICS` and
|
|
234
|
+
* `ANSWERS_PRODUCT_NAME`, typed against these interfaces — the same arrangement the concept
|
|
235
|
+
* pages use (`dev/platform/context/concepts/01-architecture.md`). A field renamed here changes
|
|
236
|
+
* every site's generated data module, so change the generator and this file together.
|
|
237
|
+
*/
|
|
215
238
|
|
|
216
|
-
|
|
239
|
+
/**
|
|
240
|
+
* One page an answer cited.
|
|
241
|
+
*
|
|
242
|
+
* Always a public URL on one of our own sites: the harness strips every link whose origin is
|
|
243
|
+
* not in its catalog before the answer is ever stored, and this is what the page renders as a
|
|
244
|
+
* real, followable link under the answer.
|
|
245
|
+
*/
|
|
246
|
+
interface PublishedAnswerSource {
|
|
247
|
+
/** Absolute `https://` URL of the page. */
|
|
248
|
+
url: string;
|
|
249
|
+
/** The page's own title, as published. */
|
|
250
|
+
title: string;
|
|
251
|
+
/** Product display name, when the page belongs to one product. */
|
|
252
|
+
product?: string;
|
|
253
|
+
}
|
|
254
|
+
/** A curated question, and the answer our assistant produced for it. */
|
|
255
|
+
interface PublishedAnswer {
|
|
256
|
+
/** Kebab-case, unique per site; the `/answer/<slug>` route. */
|
|
257
|
+
slug: string;
|
|
258
|
+
/** 1-based position across the site's answers; drives listing order and previous/next. */
|
|
259
|
+
order: number;
|
|
260
|
+
/** The question, as we wrote it. The page's `<h1>`. */
|
|
261
|
+
question: string;
|
|
262
|
+
/**
|
|
263
|
+
* The answer, as GitHub-flavoured markdown — exactly what the harness returned.
|
|
264
|
+
*
|
|
265
|
+
* It can contain GFM tables (a comparison or a plan list comes back as one; see
|
|
266
|
+
* `dev/platform/context/explore/CONTRACT.md` §7), links and concept illustrations, so it is
|
|
267
|
+
* rendered by the SAME renderer the chat uses and not by a second one.
|
|
268
|
+
*/
|
|
269
|
+
answer: string;
|
|
270
|
+
/** Grouping on the index page; matches a {@link PublishedAnswerTopic} name. */
|
|
271
|
+
topic: string;
|
|
272
|
+
/** One line under the question, on the card and in the hero. */
|
|
273
|
+
summary: string;
|
|
274
|
+
/** The `<meta name="description">` for this answer's page. */
|
|
275
|
+
metaDescription: string;
|
|
276
|
+
/** Search keywords, also used by the index page's filter. */
|
|
277
|
+
keywords: string[];
|
|
278
|
+
/** The pages the answer cited, in the order it cited them. */
|
|
279
|
+
sources: PublishedAnswerSource[];
|
|
280
|
+
/** Slugs of related answers on the same site. */
|
|
281
|
+
related: string[];
|
|
282
|
+
/**
|
|
283
|
+
* When the answer was produced, ISO-8601 (`2026-09-22`, or a full timestamp).
|
|
284
|
+
*
|
|
285
|
+
* Shown on the page and put in the structured data. An answer is a snapshot of what the
|
|
286
|
+
* documentation said on a day; publishing it without saying which day would be the one
|
|
287
|
+
* genuinely misleading thing about these pages.
|
|
288
|
+
*/
|
|
289
|
+
answeredAt: string;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Every field a {@link PublishedAnswer} has, written out once.
|
|
293
|
+
*
|
|
294
|
+
* Typed as a TOTAL map of the interface's keys: adding a field to {@link PublishedAnswer}
|
|
295
|
+
* does not compile until someone also writes it down here, and removing one does not compile
|
|
296
|
+
* until someone deletes it here. That is the point — the field that would break this feature's
|
|
297
|
+
* one rule is a conversation id, a message id or a visitor's own words, and nobody adds one of
|
|
298
|
+
* those to a published contract by accident twice.
|
|
299
|
+
*
|
|
300
|
+
* It lives in this module, not in a test, because `tsconfig.json` excludes `**\/*.test.ts(x)`
|
|
301
|
+
* from the program: a totality constraint written in a test file is never compiled and can
|
|
302
|
+
* therefore never fail. Here it is compiled by `bun run type-check`, which the PR gate and both
|
|
303
|
+
* publish workflows run, so the constraint is enforced on every path that ships this package.
|
|
304
|
+
*
|
|
305
|
+
* `answers.ssr.test.tsx` then checks the runtime half: that this list still matches the
|
|
306
|
+
* interface field for field, and that no name in it could hold a visitor's conversation. Sites
|
|
307
|
+
* generating `src/data/answers.ts` can use it the same way, to assert a generated row carries
|
|
308
|
+
* these keys and no others.
|
|
309
|
+
*/
|
|
310
|
+
declare const PUBLISHED_ANSWER_FIELDS: Record<keyof PublishedAnswer, true>;
|
|
311
|
+
interface PublishedAnswerTopic {
|
|
312
|
+
name: string;
|
|
313
|
+
description: string;
|
|
314
|
+
}
|
|
315
|
+
/** Props the pages pass to a site's link adapter. */
|
|
316
|
+
interface AnswerLinkProps {
|
|
317
|
+
href: string;
|
|
318
|
+
className?: string;
|
|
319
|
+
children: ReactNode;
|
|
320
|
+
"aria-label"?: string;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* The link the pages render for every internal URL. Sites pass a small adapter around their
|
|
324
|
+
* router's `Link`, so moving between answers stays a client-side navigation; without one the
|
|
325
|
+
* pages fall back to a plain `<a href>`.
|
|
326
|
+
*/
|
|
327
|
+
type AnswerLinkComponent = ComponentType<AnswerLinkProps>;
|
|
328
|
+
/** The index route. */
|
|
329
|
+
declare const ANSWERS_PATH = "/answers";
|
|
330
|
+
/** Prefix of every answer detail route: `/answer/<slug>`. */
|
|
331
|
+
declare const ANSWER_PATH_PREFIX = "/answer";
|
|
332
|
+
/** Site-relative URL of one answer's page. */
|
|
333
|
+
declare function answerPath(slug: string): string;
|
|
334
|
+
/**
|
|
335
|
+
* Resolve a route parameter to its answer. Returns `undefined` for an unknown slug — the site
|
|
336
|
+
* then redirects to `/answers` rather than rendering a soft 404.
|
|
337
|
+
*/
|
|
338
|
+
declare function getAnswerBySlug(answers: readonly PublishedAnswer[], slug: string | null | undefined): PublishedAnswer | undefined;
|
|
339
|
+
/**
|
|
340
|
+
* True when a source URL is safe to publish as a link.
|
|
341
|
+
*
|
|
342
|
+
* `https` only, and a real host: these pages are prerendered and crawled, so a `javascript:`
|
|
343
|
+
* or `data:` URL that reached the generated data would ship to every visitor as a live link,
|
|
344
|
+
* and a relative one would resolve against whichever answer page happened to render it. The
|
|
345
|
+
* ORIGIN allow-list belongs in the generator, which knows the catalog; this is the page's own
|
|
346
|
+
* last check, in the same spirit as the inline-image guard in the chat.
|
|
347
|
+
*/
|
|
348
|
+
declare function isPublishedSourceUrl(url: string): boolean;
|
|
349
|
+
/**
|
|
350
|
+
* The host shown beside a source, `www.` removed.
|
|
351
|
+
*
|
|
352
|
+
* Same normalisation the chat's reference cards apply, so a source reads the same way whether
|
|
353
|
+
* a visitor met it in a conversation or on one of these pages. Returns `""` for anything
|
|
354
|
+
* unparseable — the label is decorative, and {@link isPublishedSourceUrl} has already decided
|
|
355
|
+
* whether the link renders at all.
|
|
356
|
+
*/
|
|
357
|
+
declare function answerSourceHost(url: string): string;
|
|
217
358
|
|
|
359
|
+
interface AnswersPageProps {
|
|
360
|
+
/** Product display name, e.g. `"VibeControls"`. */
|
|
361
|
+
productName: string;
|
|
362
|
+
/** Public origin of the site, e.g. `"https://vibecontrols.com"`. Used for absolute URLs. */
|
|
363
|
+
siteUrl: string;
|
|
364
|
+
answers: readonly PublishedAnswer[];
|
|
365
|
+
/** Section order and descriptions. Answers in an unlisted topic still render, last. */
|
|
366
|
+
topics?: readonly PublishedAnswerTopic[];
|
|
367
|
+
/** Call to action rendered in the hero (e.g. the site's primary buttons). */
|
|
368
|
+
cta?: ReactNode;
|
|
369
|
+
/** Router adapter for internal links. Defaults to a plain `<a href>`. */
|
|
370
|
+
linkComponent?: AnswerLinkComponent;
|
|
371
|
+
/** Overrides the `<h1>`. Default: the localised `"<productName> answers"`. */
|
|
372
|
+
title?: string;
|
|
373
|
+
/** Overrides the meta description and the hero lead. */
|
|
374
|
+
description?: string;
|
|
375
|
+
/**
|
|
376
|
+
* BCP-47 locale for the page chrome. Defaults to the document's own `lang`, then the
|
|
377
|
+
* browser. The ANSWERS themselves are English whatever this says — see `answers-i18n.ts`.
|
|
378
|
+
*/
|
|
379
|
+
locale?: string;
|
|
380
|
+
/** Extra classes for the page root. */
|
|
381
|
+
className?: string;
|
|
382
|
+
}
|
|
383
|
+
interface AnswerDetailPageProps {
|
|
384
|
+
productName: string;
|
|
385
|
+
siteUrl: string;
|
|
386
|
+
/** The answer to render. The site resolves the slug and redirects when it is unknown. */
|
|
387
|
+
answer: PublishedAnswer;
|
|
388
|
+
/** Every answer on the site — for related questions and previous / next. */
|
|
389
|
+
answers: readonly PublishedAnswer[];
|
|
390
|
+
topics?: readonly PublishedAnswerTopic[];
|
|
391
|
+
/**
|
|
392
|
+
* Extra origins an illustration embedded in the answer may load from.
|
|
393
|
+
*
|
|
394
|
+
* The site's own origin and the origins of this answer's sources are always allowed, which
|
|
395
|
+
* covers every image the harness can legitimately have embedded. Pass more only when an
|
|
396
|
+
* answer cites a page whose images live elsewhere in the catalog, and pass a stable array.
|
|
397
|
+
*/
|
|
398
|
+
imageOrigins?: readonly string[];
|
|
399
|
+
/**
|
|
400
|
+
* Where "Ask your own question" goes. `null` removes the link — pass that on a site with no
|
|
401
|
+
* `/explore` route, rather than shipping a link to a page that does not exist.
|
|
402
|
+
*/
|
|
403
|
+
askHref?: string | null;
|
|
404
|
+
/** Call to action rendered as a band at the end of the page. */
|
|
405
|
+
cta?: ReactNode;
|
|
406
|
+
linkComponent?: AnswerLinkComponent;
|
|
407
|
+
locale?: string;
|
|
408
|
+
className?: string;
|
|
409
|
+
}
|
|
218
410
|
/**
|
|
219
|
-
*
|
|
411
|
+
* Heading overrides for a PUBLISHED answer, merged over the shared answer components.
|
|
220
412
|
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
413
|
+
* In the chat an answer is one message in a stream and its `#` headings bother nobody. On a
|
|
414
|
+
* crawled page the outline is the page's structure: the question is the `<h1>` and "Answer"
|
|
415
|
+
* is an `<h2>`, so an answer that opens with `## Plans` would put a second `<h2>` inside a
|
|
416
|
+
* section and an answer that opens with `#` would put a SECOND `<h1>` on the page. Both are
|
|
417
|
+
* things a crawler reads as the page changing subject.
|
|
418
|
+
*
|
|
419
|
+
* So every heading the model wrote is pushed below the page's own: `#` and `##` become `<h3>`
|
|
420
|
+
* (the first real level inside the answer section), and the rest follow, floored at `<h6>`.
|
|
421
|
+
* The words are untouched — only the level moves.
|
|
422
|
+
*
|
|
423
|
+
* Module-level on purpose: react-markdown uses an override as the element TYPE, so rebuilding
|
|
424
|
+
* this object during a render would remount everything under it.
|
|
223
425
|
*/
|
|
224
|
-
declare const
|
|
426
|
+
declare const ANSWER_HEADING_SHIFT: Components;
|
|
427
|
+
/**
|
|
428
|
+
* `/answers` — every published answer on the site, grouped by topic, with a client-side
|
|
429
|
+
* search and topic filter. Filters start at "All", so the prerendered page lists everything.
|
|
430
|
+
*/
|
|
431
|
+
declare function AnswersPage({ productName, siteUrl, answers, topics, cta, linkComponent, title, description, locale, className, }: AnswersPageProps): react.JSX.Element;
|
|
432
|
+
/**
|
|
433
|
+
* `/answer/:slug` — one question, the answer, and the pages it came from.
|
|
434
|
+
*/
|
|
435
|
+
declare function AnswerDetailPage(props: AnswerDetailPageProps): react.JSX.Element;
|
|
225
436
|
|
|
226
437
|
/**
|
|
227
438
|
* Localisation for the `/explore` chat surface.
|
|
@@ -296,6 +507,38 @@ interface ExploreStrings {
|
|
|
296
507
|
feedbackDismiss: string;
|
|
297
508
|
feedbackThanks: string;
|
|
298
509
|
feedbackNotSent: string;
|
|
510
|
+
/**
|
|
511
|
+
* The trigger, in its two homes: `escalateOpen` is the quiet one under an answer we DID
|
|
512
|
+
* give, and the amber "we could not find this" banner reuses `askHuman` so that sentence
|
|
513
|
+
* keeps reading as one sentence.
|
|
514
|
+
*/
|
|
515
|
+
escalateOpen: string;
|
|
516
|
+
escalateTitle: string;
|
|
517
|
+
escalateBody: string;
|
|
518
|
+
escalateEmailLabel: string;
|
|
519
|
+
escalateEmailPlaceholder: string;
|
|
520
|
+
escalateNoteLabel: string;
|
|
521
|
+
escalateSubmit: string;
|
|
522
|
+
escalateSending: string;
|
|
523
|
+
escalateCancel: string;
|
|
524
|
+
/**
|
|
525
|
+
* Shown for BOTH the client's own pre-flight and the server's `INVALID_EMAIL`. The two
|
|
526
|
+
* disagree about what is deliverable and the server is right, but the visitor's next
|
|
527
|
+
* action is identical either way: check the address.
|
|
528
|
+
*/
|
|
529
|
+
escalateInvalidEmail: string;
|
|
530
|
+
/**
|
|
531
|
+
* The success line. Takes `{email}` — and it is filled with the address the SERVER
|
|
532
|
+
* returned, not the one in the box, because on a repeat handover the reply goes to
|
|
533
|
+
* whichever address the first one used.
|
|
534
|
+
*
|
|
535
|
+
* Used for `created: false` as well: a visitor asking for help is not told "you already
|
|
536
|
+
* did that".
|
|
537
|
+
*/
|
|
538
|
+
escalateSent: string;
|
|
539
|
+
escalateRateLimited: string;
|
|
540
|
+
escalateCaptcha: string;
|
|
541
|
+
escalateFailed: string;
|
|
299
542
|
prevSuggestion: string;
|
|
300
543
|
nextSuggestion: string;
|
|
301
544
|
/**
|
|
@@ -367,4 +610,153 @@ interface ExploreStrings {
|
|
|
367
610
|
}
|
|
368
611
|
declare function speechLocaleOf(locale: ExploreLocale): string;
|
|
369
612
|
|
|
370
|
-
|
|
613
|
+
/**
|
|
614
|
+
* Localisation for the published answer pages.
|
|
615
|
+
*
|
|
616
|
+
* Same arrangement, and the same reasons, as `explore-i18n.ts`: the strings are bundled
|
|
617
|
+
* rather than fetched, because these pages are prerendered and a runtime translation request
|
|
618
|
+
* in front of the first paint would defeat the point of prerendering them. The locale set,
|
|
619
|
+
* the resolver and the `{placeholder}` filler are IMPORTED from there rather than repeated —
|
|
620
|
+
* one locale list for the whole explore surface, so a seventh language is added in one place.
|
|
621
|
+
*
|
|
622
|
+
* ## What is localised, and what is not
|
|
623
|
+
*
|
|
624
|
+
* The chrome — headings, labels, the provenance note, the breadcrumb — is localised into the
|
|
625
|
+
* six locales the products ship. **The answer itself is English**, because that is what the
|
|
626
|
+
* harness produced for the curated English question; nothing here translates it, and nothing
|
|
627
|
+
* here pretends it is translated.
|
|
628
|
+
*
|
|
629
|
+
* That split is also MARKED UP, not merely true: the pages carry `dir="rtl"` on their own
|
|
630
|
+
* subtree in Arabic (`isRtlLocale`, re-exported here so the pages have one locale module), and
|
|
631
|
+
* put `lang="en"` on the English content inside it. A page that declares itself Arabic and
|
|
632
|
+
* then prints an English answer tells a screen reader to read English with Arabic phonemes,
|
|
633
|
+
* and tells a crawler the answer is in a language it is not.
|
|
634
|
+
*
|
|
635
|
+
* ## The three borrowed strings
|
|
636
|
+
*
|
|
637
|
+
* `answerTable`, `conceptIllustration` and `opensInNewTab` come straight from
|
|
638
|
+
* `exploreStrings`. They are the words the ANSWER BODY renders, and the answer body is the
|
|
639
|
+
* same component on both surfaces — two phrasings for the same caveat read as two different
|
|
640
|
+
* caveats, which is the rule the illustration badge already follows.
|
|
641
|
+
*/
|
|
642
|
+
|
|
643
|
+
interface AnswerStrings extends AnswerRendererStrings {
|
|
644
|
+
breadcrumbHome: string;
|
|
645
|
+
/** The section's own name: breadcrumb, nav item, back link. */
|
|
646
|
+
answers: string;
|
|
647
|
+
/** The index page's `<h1>`. Takes `{product}`. */
|
|
648
|
+
indexHeading: string;
|
|
649
|
+
/** The lead under it. Takes `{product}`. */
|
|
650
|
+
indexLead: string;
|
|
651
|
+
/** `<title>` of the index page; PageHead appends the product name itself. */
|
|
652
|
+
seoIndexTitle: string;
|
|
653
|
+
/** Its `<meta name="description">`. Takes `{product}`. */
|
|
654
|
+
seoIndexDescription: string;
|
|
655
|
+
searchLabel: string;
|
|
656
|
+
searchPlaceholder: string;
|
|
657
|
+
filterByTopic: string;
|
|
658
|
+
allTopics: string;
|
|
659
|
+
/** Takes `{shown}` and `{total}`. */
|
|
660
|
+
showingCount: string;
|
|
661
|
+
noMatchesTitle: string;
|
|
662
|
+
noMatchesBody: string;
|
|
663
|
+
clearFilters: string;
|
|
664
|
+
noneYetTitle: string;
|
|
665
|
+
/** Takes `{product}`. */
|
|
666
|
+
noneYetBody: string;
|
|
667
|
+
questionCountOne: string;
|
|
668
|
+
/** Takes `{count}`. */
|
|
669
|
+
questionCountMany: string;
|
|
670
|
+
sourceCountOne: string;
|
|
671
|
+
/** Takes `{count}`. */
|
|
672
|
+
sourceCountMany: string;
|
|
673
|
+
answerHeading: string;
|
|
674
|
+
sourcesHeading: string;
|
|
675
|
+
sourcesLead: string;
|
|
676
|
+
aboutTitle: string;
|
|
677
|
+
/**
|
|
678
|
+
* The honest description of what the reader is looking at. Takes `{date}`.
|
|
679
|
+
*
|
|
680
|
+
* Every clause is load-bearing, and the wording was chosen against the alternatives:
|
|
681
|
+
*
|
|
682
|
+
* - **"Produced by our own assistant"** — not "written by our team", which would be false,
|
|
683
|
+
* and not "AI-powered answers", which is marketing language for a disclosure.
|
|
684
|
+
* - **"on {date}"** — an answer is a snapshot of what the documentation said on a day. The
|
|
685
|
+
* single genuinely misleading thing these pages could do is present a year-old answer as
|
|
686
|
+
* current, so the date is in the sentence rather than in small print beside it.
|
|
687
|
+
* - **"The pages it drew on are linked under the answer"** — it tells the reader where to
|
|
688
|
+
* check, which is the only thing that makes the rest of the note actionable.
|
|
689
|
+
* - **"not a statement from a person"** — the sentence people actually need. This is a
|
|
690
|
+
* marketing surface, and a visitor who takes a generated paragraph for a commitment from
|
|
691
|
+
* us has been misled by us.
|
|
692
|
+
* - **"where it and a linked page disagree, the page is right"** — says which source wins,
|
|
693
|
+
* instead of a hedge ("may contain errors") that tells nobody what to do about it.
|
|
694
|
+
*
|
|
695
|
+
* Deliberately NOT said: that the answers are "frequently asked" or "the questions our
|
|
696
|
+
* customers ask most". They are a question set we chose. We have no measurement behind a
|
|
697
|
+
* popularity claim — and the one table that could measure it is the visitor question log,
|
|
698
|
+
* which this feature must never read (see `answers-types.ts`).
|
|
699
|
+
*/
|
|
700
|
+
aboutBody: string;
|
|
701
|
+
/** Takes `{date}`. */
|
|
702
|
+
answeredOn: string;
|
|
703
|
+
topicsHeading: string;
|
|
704
|
+
relatedHeading: string;
|
|
705
|
+
/** Takes `{topic}`. */
|
|
706
|
+
moreInTopic: string;
|
|
707
|
+
previousQuestion: string;
|
|
708
|
+
nextQuestion: string;
|
|
709
|
+
/** Takes `{product}`. */
|
|
710
|
+
allAnswers: string;
|
|
711
|
+
askYourOwn: string;
|
|
712
|
+
}
|
|
713
|
+
declare function answerStrings(locale: ExploreLocale): AnswerStrings;
|
|
714
|
+
/**
|
|
715
|
+
* `answeredAt` as a date a person reads.
|
|
716
|
+
*
|
|
717
|
+
* Two things are pinned rather than left to the environment, because these pages are
|
|
718
|
+
* serialised from the post-hydration DOM: the machine that prerenders them and the browser
|
|
719
|
+
* that hydrates them must produce the SAME string, or React replaces the node on hydration.
|
|
720
|
+
*
|
|
721
|
+
* - **An explicit locale tag**, never the ambient default — the prerender runs in headless
|
|
722
|
+
* Chromium on a server whose locale is nobody's.
|
|
723
|
+
* - **An explicit numbering system.** CLDR has changed the default digits for `ar` before;
|
|
724
|
+
* two engines on different CLDR versions would then render the same date differently, and
|
|
725
|
+
* the text React hydrated would not be the text it prerendered. All six locales already
|
|
726
|
+
* default to Latin digits, so this pins today's output rather than changing it.
|
|
727
|
+
* - **`timeZone: "UTC"`**, because `new Date("2026-09-22")` is UTC midnight and formatting it
|
|
728
|
+
* in a negative-offset zone would print the 21st. A published date that moves by a day
|
|
729
|
+
* depending on who looks at it is worse than no date.
|
|
730
|
+
*
|
|
731
|
+
* Returns `""` for an unparseable value so a bad row loses its date line rather than printing
|
|
732
|
+
* "Invalid Date" on a marketing page.
|
|
733
|
+
*/
|
|
734
|
+
declare function formatAnswerDate(value: string, locale: ExploreLocale): string;
|
|
735
|
+
|
|
736
|
+
declare const buttonVariants: (props?: ({
|
|
737
|
+
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
738
|
+
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
739
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
740
|
+
interface ButtonProps extends react.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
741
|
+
asChild?: boolean;
|
|
742
|
+
}
|
|
743
|
+
declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
744
|
+
|
|
745
|
+
declare const Input: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & react.RefAttributes<HTMLInputElement>>;
|
|
746
|
+
|
|
747
|
+
declare const Label: react.ForwardRefExoticComponent<Omit<LabelPrimitive.LabelProps & react.RefAttributes<HTMLLabelElement>, "ref"> & VariantProps<(props?: class_variance_authority_types.ClassProp | undefined) => string> & react.RefAttributes<HTMLLabelElement>>;
|
|
748
|
+
|
|
749
|
+
/** Native `<select>` wrapper matching the `Input` design tokens. */
|
|
750
|
+
declare const Select: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>, "ref"> & react.RefAttributes<HTMLSelectElement>>;
|
|
751
|
+
|
|
752
|
+
declare const Textarea: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "ref"> & react.RefAttributes<HTMLTextAreaElement>>;
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Canonical Burdenoff ecosystem product list used by WebsiteSwitcher.
|
|
756
|
+
*
|
|
757
|
+
* Sourced from `~/products/websites/burdenoff-website/src/data/products.ts`.
|
|
758
|
+
* Keep this in sync when products are added, renamed, or moved.
|
|
759
|
+
*/
|
|
760
|
+
declare const ECOSYSTEM_PRODUCTS: WebsiteSwitcherProduct[];
|
|
761
|
+
|
|
762
|
+
export { ANSWERS_PATH, ANSWER_HEADING_SHIFT, ANSWER_PATH_PREFIX, AnswerDetailPage, type AnswerDetailPageProps, type AnswerLinkComponent, type AnswerLinkProps, AnswerRendererStrings, type AnswerStrings, AnswersPage, type AnswersPageProps, Button, type ButtonProps, CONCEPTS_PATH, CONCEPT_ILLUSTRATION_NOTICE, CONCEPT_PATH_PREFIX, CareersPostingOption, CareersSubmissionForm, type CareersSubmissionFormProps, type Concept, type ConceptCategory, ConceptDetailPage, type ConceptDetailPageProps, type ConceptDevice, type ConceptImage, type ConceptLinkComponent, type ConceptLinkProps, ConceptsPage, type ConceptsPageProps, ECOSYSTEM_PRODUCTS, EXPLORE_LOCALES, type ExploreLocale, type ExploreStrings, Input, Label, PUBLISHED_ANSWER_FIELDS, type PublishedAnswer, type PublishedAnswerSource, type PublishedAnswerTopic, Select, Textarea, WebsiteSwitcherProduct, answerPath, answerSourceHost, answerStrings, buttonVariants, conceptPath, formatAnswerDate, getAnswerBySlug, getConceptBySlug, isPublishedSourceUrl, isValidUrl, speechLocaleOf };
|