/** * Public types for `featurebase-js`. * * The runtime (sdk.js) consumes camelCase fields. This SDK accepts both * camelCase (preferred) and snake_case aliases for ergonomics in apps that * use snake_case keys throughout, and normalizes everything to camelCase * before dispatching. */ type ThemeMode = 'light' | 'dark'; /** * Pages the messenger can be opened to via `show()`. * * Unknown values are forwarded to the runtime as-is for forward * compatibility with future spaces. */ type Space = 'home' | 'messages' | 'help' | 'changelog' | (string & {}); /** * Optional company association for the identified user. */ interface FeaturebaseCompany { /** Stable company identifier in your system. */ companyId?: string; /** Snake_case alias for {@link FeaturebaseCompany.companyId}. */ company_id?: string; name?: string; createdAt?: number | string; /** Snake_case alias for {@link FeaturebaseCompany.createdAt}. */ created_at?: number | string; monthlySpend?: number; /** Snake_case alias for {@link FeaturebaseCompany.monthlySpend}. */ monthly_spend?: number; plan?: string; size?: number; website?: string; industry?: string; /** Arbitrary additional company attributes. */ [key: string]: unknown; } /** * Settings accepted by `Featurebase()` / `boot()` / `update()`. * * Both camelCase (preferred) and snake_case aliases are accepted for every * field. The wrapper normalizes to camelCase before dispatching to the * runtime. */ interface FeaturebaseSettings { /** * Your Featurebase organization id (the value the dashboard's * **Settings → Support → Installation** copy labels as `appId`). The * single field that drives both the messenger and the standalone * widgets — the SDK resolves it once to `{ slug, modules }` via * `https://do.featurebase.app/v1/organization/by-id/:appId` and uses * the workspace's **General → Manage modules** toggles to decide which * surfaces auto-boot. */ appId?: string; /** Snake_case alias for {@link FeaturebaseSettings.appId}. */ app_id?: string; /** * Opt out of the support messenger even when **Manage modules** has * Support enabled. Most apps don't need this — leave it unset and the * SDK boots the messenger only when the workspace has Support on. * * Set to `false` when you want to manage the messenger yourself * (different page, different timing, etc.) without touching the * dashboard module flags. Default `true`. */ messenger?: boolean; /** Stable user id in your system. */ userId?: string | number; /** Snake_case alias for {@link FeaturebaseSettings.userId}. */ user_id?: string | number; email?: string; name?: string; /** * Server-signed JWT carrying the user's identity and custom attributes. * **Recommended** auth method — see * https://help.featurebase.app/en/articles/5257986-creating-and-signing-a-jwt * * @example * Featurebase({ appId, featurebaseJwt: serverSignedJwt }); */ featurebaseJwt?: string; /** * @deprecated Use {@link FeaturebaseSettings.featurebaseJwt} instead. * `userHash` (HMAC) is the legacy auth method and is being phased out. * See https://help.featurebase.app/en/help/articles/5402549-secure-your-installation-required-by-default */ userHash?: string; /** * @deprecated Use {@link FeaturebaseSettings.featurebaseJwt} instead. * Snake_case alias for the legacy {@link FeaturebaseSettings.userHash}. */ user_hash?: string; createdAt?: number | string; /** Snake_case alias for {@link FeaturebaseSettings.createdAt}. */ created_at?: number | string; company?: FeaturebaseCompany; companies?: FeaturebaseCompany[]; /** Optional brand id when running multi-brand. */ $brandId?: string; theme?: ThemeMode; /** Alternate spelling of {@link FeaturebaseSettings.theme}. */ themeMode?: ThemeMode; /** Snake_case alias for {@link FeaturebaseSettings.themeMode}. */ theme_mode?: ThemeMode; language?: string; /** Alternate spelling of {@link FeaturebaseSettings.language}. */ languageOverride?: string; /** Snake_case alias for {@link FeaturebaseSettings.languageOverride}. */ language_override?: string; hideDefaultLauncher?: boolean; /** Snake_case alias for {@link FeaturebaseSettings.hideDefaultLauncher}. */ hide_default_launcher?: boolean; alignment?: 'left' | 'right'; horizontalPadding?: number; /** Snake_case alias for {@link FeaturebaseSettings.horizontalPadding}. */ horizontal_padding?: number; verticalPadding?: number; /** Snake_case alias for {@link FeaturebaseSettings.verticalPadding}. */ vertical_padding?: number; actionColor?: string; /** Snake_case alias for {@link FeaturebaseSettings.actionColor}. */ action_color?: string; backgroundColor?: string; /** Snake_case alias for {@link FeaturebaseSettings.backgroundColor}. */ background_color?: string; customData?: Record; /** Snake_case alias for {@link FeaturebaseSettings.customData}. */ custom_data?: Record; /** * Any additional attributes are passed through to the runtime untouched * and end up on the contact's profile (Featurebase's catchall). */ [key: string]: unknown; } /** Internal: shape after `normalizeSettings()` resolves all aliases. */ interface NormalizedFeaturebaseSettings { appId: string; [key: string]: unknown; } /** * BCP-47 short codes accepted by every Featurebase widget. Mirrors the * runtime's `localeShortCodeSchema`. Unknown codes are forwarded verbatim * to the runtime for forward compatibility. */ type FeaturebaseLocale = 'bn' | 'bs' | 'pt-BR' | 'bg' | 'ca' | 'hr' | 'cs' | 'da' | 'nl' | 'en' | 'et' | 'fi' | 'fr' | 'de' | 'el' | 'hi' | 'hu' | 'id' | 'it' | 'ja' | 'ko' | 'lv' | 'lt' | 'ms' | 'mn' | 'nb' | 'pl' | 'pt' | 'ro' | 'ru' | 'sr' | 'zh-CN' | 'sl' | 'es' | 'sw' | 'sv' | 'th' | 'zh-TW' | 'tr' | 'uk' | 'vi' | 'sk' | (string & {}); /** * Identity fields every widget accepts. Pass `featurebaseJwt` (a * server-signed JWT carrying the user's identity and custom attributes) * — this is the recommended auth method. * * See https://help.featurebase.app/en/articles/5257986-creating-and-signing-a-jwt */ interface FeaturebaseWidgetIdentity { /** * Server-signed JWT carrying the user's identity. **Recommended.** */ featurebaseJwt?: string; /** * Pre-minted JWT (advanced — most apps should use `featurebaseJwt`). */ jwtToken?: string; /** * Plain-text email. Only safe when the attribute is explicitly * configured as non-secured in the dashboard. Prefer the JWT. */ email?: string; /** * Plain-text user id. Only safe when the attribute is explicitly * configured as non-secured in the dashboard. Prefer the JWT. */ userId?: string; /** * @deprecated Use {@link FeaturebaseWidgetIdentity.featurebaseJwt} instead. * `userHash` (HMAC) is the legacy auth method and is being phased out. */ userHash?: string; } /** * Shared base for every standalone widget config (caller-facing). The * workspace slug is resolved from the appId set on * `Featurebase({ appId })` / `` and is never a * per-widget input. */ interface FeaturebaseWidgetBase extends FeaturebaseWidgetIdentity { /** Widget locale. Defaults to `'en'` when omitted. */ locale?: FeaturebaseLocale; } /** * Modern changelog widget config (uses `dropdown` / `popup` / `changelogCard` * sub-objects). At least one of the three must be enabled. * * Use {@link initChangelog} to dispatch. */ interface ChangelogWidgetConfig extends FeaturebaseWidgetBase { /** Optional category slugs to filter the widget contents by. */ category?: string[]; /** Theme for the widget shell. */ theme: 'dark' | 'light'; /** Bind to a target selector and render a dropdown panel of updates. */ dropdown?: { enabled: boolean; placement?: 'bottom' | 'top' | 'left' | 'right' | 'auto'; /** Lazy-load the dropdown contents on first open. */ lazyLoad?: boolean; }; /** Auto-display a fullscreen popup of the latest unread update. */ popup?: { enabled: boolean; /** Used to personalize the popup greeting. */ usersName?: string; /** If true, the popup re-opens whenever a new update is published. */ autoOpenForNewUpdates?: boolean; }; /** Floating bottom-corner card that announces the latest update. */ changelogCard?: { enabled: boolean; /** Open the linked update in a new tab when the card is clicked. */ openInNewTab?: boolean; layout?: { position?: 'bottom-left' | 'bottom-right'; marginBottom?: number; marginSide?: number; maxWidth?: number; }; /** Override the card's default styling. */ theme?: { borderRadius?: number; backgroundColor?: string; titleColor?: string; descriptionColor?: string; borderColor?: string; }; }; } /** * Legacy changelog widget config (single `placement`). Kept for * backward-compatibility with installations that booted before the new * dropdown/popup/card split. Prefer {@link ChangelogWidgetConfig} for new * code. */ interface LegacyChangelogWidgetConfig extends FeaturebaseWidgetBase { /** Theme for the widget shell. */ theme: string; placement?: 'bottom' | 'top' | 'left' | 'right' | 'auto'; fullscreenPopup?: boolean; /** Personalizes the popup greeting. */ usersName?: string; /** If true, popup opens regardless of unread state. */ alwaysShow?: boolean; /** Lazy-load the dropdown contents on first open. */ lazyLoadDropdown?: boolean; } /** * Floating feedback button. Pops out a panel where users can browse and * submit posts to your Featurebase boards. * * Use {@link initFeedbackWidget} to dispatch. */ interface FeedbackWidgetConfig extends FeaturebaseWidgetBase { /** Theme for the widget shell. */ theme: string; placement?: 'bottom-right' | 'bottom-left' | 'left' | 'right'; /** Slug of the board to open by default. */ defaultBoard?: string; /** Arbitrary string-valued attributes attached to submitted posts. */ metadata?: Record | null; } /** * Survey runtime config. The widget fetches the active surveys for your * organization and auto-displays them based on the targeting rules * configured in your dashboard (URL match, CSS selector, segment). * * Use {@link initSurveys} to dispatch. */ interface SurveyWidgetConfig extends FeaturebaseWidgetBase { placement?: 'bottom-left' | 'bottom-right' | null; /** Theme override. Defaults to the survey's own configured theme. */ theme?: string; } /** * Surface returned to the embed callback by the runtime. Forward-compat: * unknown `action` strings are surfaced verbatim. */ type FeaturebaseEmbedAction = 'loaded' | 'widgetReady' | 'routeChange' | (string & {}); /** * Callback signature shared by both embed APIs. The runtime invokes this * for lifecycle events (`loaded`, `widgetReady`, …) and route changes from * inside the iframe. */ type FeaturebaseEmbedCallback = (error: Error | null, data: ({ action?: FeaturebaseEmbedAction; } & Record) | null) => void; /** * Modern embeddable board config. Mounts the Featurebase board into a * `[data-featurebase-embed]` element on the host page. * * Use {@link initEmbedWidget} to dispatch. */ interface FeaturebaseEmbedWidgetConfig extends FeaturebaseWidgetBase { /** * Per-mount overrides forwarded to the iframe. * * **Identity (`appId`, `userId`, `email`, `featurebaseJwt`) is wrapper- * managed** — pass it once to {@link configure}, the unified * `Featurebase({ appId, featurebaseJwt })` entry point, or the React * ``. The wrapper auto-forwards it to every * embed mount; you should not pass identity here. * * The `metadata` field is the only thing you'd typically set per * mount — it attaches arbitrary string attributes to posts / votes * submitted from inside the iframe (e.g. plan, app version). * * @internal `user.jwt` is kept on the type only to match the * underlying runtime contract for advanced power-users; new code * should rely on the universal install above instead. */ user?: { /** @deprecated Use the universal `featurebaseJwt` from setup instead. */ jwt?: string | null; /** Arbitrary string attributes attached to posts / votes submitted from the iframe. */ metadata?: Record; }; /** Cosmetic overrides for the embedded portal. */ stylingOptions?: { /** * Hide the top navigation bar inside the iframe (the Boards / Roadmap / * Changelog tabs). Useful when you're embedding a single surface * (e.g. just `/roadmap`) and the host page already has its own * navigation. Defaults to `false`. */ hideMenu?: boolean; /** Hide the Featurebase logo in the navigation bar. Defaults to `false`. */ hideLogo?: boolean; /** * Force a theme inside the iframe. * - `'light'` / `'dark'` — explicit theme. * - `''` — auto-detect from the visitor's `prefers-color-scheme`. * - omitted / `null` — fall back to the workspace default theme. */ theme?: 'light' | 'dark' | '' | null; }; /** * Where to mount inside the embedded portal. Required by the runtime * (defaults to `'/'` — the boards index — when omitted at the field * level). */ embedOptions: { /** * Path inside the portal to load on mount. * - `'/'` — feedback boards index (default). * - `'/roadmap'` — roadmap. * - `'/changelog'` — changelog. * - `'/p/'` — a specific post. */ path?: string | null; /** * Query-string filters applied to the mounted page (without the * leading `?`). Example: `'b=63f827df2d62cb301468aac4&sortBy=upvotes:desc'` * pre-filters the boards index to a specific board, sorted by upvotes. */ filters?: string | null; /** * **Advanced.** Reflect iframe route changes onto the host URL under * this prefix so users can deep-link / use the browser back button. * Example: `'/feedback'` makes the host URL become `'/feedback/p/abc123'` * when the visitor opens a post inside the iframe. Defaults to no * syncing. */ routeSyncingBasePath?: string | null; }; } /** Widget identity fields that are inheritable from the Provider. */ type InheritableIdentity = Partial; /** Loose changelog config: identity inheritable from context. */ type ChangelogWidgetConfigInput = Omit & { locale?: FeaturebaseLocale; } & InheritableIdentity; /** Loose legacy-changelog config: identity inheritable. */ type LegacyChangelogWidgetConfigInput = Omit & { locale?: FeaturebaseLocale; } & InheritableIdentity; /** Loose feedback config: identity inheritable. */ type FeedbackWidgetConfigInput = Omit & { locale?: FeaturebaseLocale; } & InheritableIdentity; /** Loose survey config: identity inheritable. */ type SurveyWidgetConfigInput = Omit & { locale?: FeaturebaseLocale; } & InheritableIdentity; /** Loose modern embed widget config: identity inheritable. */ type FeaturebaseEmbedWidgetConfigInput = Omit & { locale?: FeaturebaseLocale; } & InheritableIdentity; /** Window augmentation for the global command queue. */ declare global { interface Window { Featurebase?: FeaturebaseGlobal; } } /** * The global `window.Featurebase` function. While the runtime is loading it * is a queue stub; once `sdk.js` is ready the runtime replaces it with a * real dispatcher and drains `q`. */ interface FeaturebaseGlobal { (action: string, data?: unknown, callback?: (...args: unknown[]) => void): unknown; q?: unknown[][]; } /** * `featurebase-js` — typed wrapper around the Featurebase Messenger runtime. * * The runtime (`sdk.js`) is a global command queue: every method call below * is dispatched as `window.Featurebase(action, data, callback?)`. While the * runtime is still loading, calls are buffered in `window.Featurebase.q` * and drained once the script tag executes. * * This wrapper: * - is SSR-safe (every export is a no-op when `window` is undefined), * - auto-injects the runtime `