/** * A purchasable item defined by a publisher for their application. * Items are session-scoped; they expire when the session ends. */ export declare interface ApplicationItem { /** Unique item identifier (UUID) */ id: string; /** Display name (3–80 characters) */ name: string; /** Item description (0–500 characters) */ description: string; /** Publisher's USD rate per purchase (e.g. 2.00) */ baseRateUsd: number; /** Derived wholesale token cost: floor(baseRateUsd / 0.10) */ wholesaleTokenCost: number; /** Derived user token cost: ceil(baseRateUsd * 1.35 / 0.10) */ userTokenCost: number; /** Lifecycle status — inactive blocks purchases */ status: "active" | "inactive" | "deleted"; /** Display visibility — hidden items are sold only via requestPurchase */ visibility: "visible" | "hidden"; /** Optimistic locking version */ version: number; /** ISO 8601 creation timestamp */ createdAt: string; /** ISO 8601 last-updated timestamp */ updatedAt: string; /** * Minimum Privy level required to purchase this item. * 0 = no Privy requirement; 1 = Privy 1 required. * When > 0, item cards should display a Privy badge. */ minimumPrivyLevel?: number; } /** Defines visibility and access restrictions for a catalog item. */ declare interface Audience { type: AudienceType; grants?: GrantRef[]; } /** Audience restriction type for a catalog item. */ declare type AudienceType = "ORG_ALLOWLIST" | "GRANT_REQUIRED"; export declare interface AutocompleteResponse { results: AutocompleteResult[]; query: string; } export declare interface AutocompleteResult { id: string; name: string; itemType: string; score: number; } /** * Create an SDK configuration for a specific environment * * This helper function simplifies SDK initialization by automatically * applying environment-specific defaults while allowing overrides. * * @param environment - The target environment ('production' or 'demo') * @param overrides - Optional configuration overrides * @returns Complete SDK configuration with environment defaults * * @example * ```typescript * // Simple usage * const sdk = new MarketplaceSDK(createSDKConfig('demo', { * applicationId: 'my-app' * })); * * // With custom overrides * const sdk = new MarketplaceSDK(createSDKConfig('demo', { * applicationId: 'my-app', * debug: true, * warningThresholdSeconds: 120 * })); * ``` */ export declare function createSDKConfig(environment: Environment, overrides?: Partial): SDKConfig; /** * Dark theme matching gw-spa design system */ export declare const darkTheme: Theme; /** * Duration Slider component for selecting extension duration. * DOM-based component (no React dependency) for maximum compatibility. */ export declare class DurationSlider { private container; private theme; private options; constructor(themeMode?: ThemeMode); private detectDarkMode; /** * Format minutes into a human-readable duration string. */ private formatDuration; /** * Render the slider into a container element. */ render(parent: HTMLElement, options: DurationSliderOptions): void; /** * Inject CSS for slider thumb styling (cross-browser). */ private injectSliderStyles; /** * Update the slider value programmatically. */ updateValue(minutes: number): void; /** * Get the current slider value. */ getValue(): number; /** * Remove the slider from the DOM. */ destroy(): void; } export declare interface DurationSliderOptions { /** Minimum allowed minutes */ min: number; /** Maximum allowed minutes */ max: number; /** Current/initial value in minutes */ value: number; /** Step increment in minutes (default: 15) */ step?: number; /** Callback when value changes */ onChange: (minutes: number) => void; } export declare interface EngagementTrackRequest { catalogItemId: string; catalogItemType: "APPLICATION" | "DATASET" | "SERVICE"; eventType: "CLICK" | "VIEW" | "SESSION_LAUNCH" | "DATASET_QUERY" | "RFI_SUBMIT"; searchRequestId?: string; } export declare interface EnrichedResult { id: string; matchReason: string | null; relevanceScore: number; } /** * Environment Configuration Types * * Defines environment-specific configuration for the SDK. */ /** * Available environments for the SDK */ export declare type Environment = "production" | "demo" | "dev"; /** * Pre-configured environment settings */ export declare const ENVIRONMENT_CONFIGS: Record; /** * Environment-specific configuration */ export declare interface EnvironmentConfig { /** JWKS endpoint URL for JWT signature verification */ jwksUri: string; /** SDK API endpoint for all backend operations */ apiEndpoint: string; /** Marketplace URL for redirects */ marketplaceUrl: string; /** Expected JWT issuer for validation */ issuer: string; } /** * Options for extendSession() */ export declare interface ExtendSessionOptions { /** * If true, skip PurchaseModal and call the extend API directly. * Default: false (shows PurchaseModal or falls back to onExtend) */ skipConfirmation?: boolean; /** * Desired extension duration in minutes. * Must be between minExtensionMinutes and maxExtensionMinutes from getExtensionCost(). * If omitted, uses the default extension duration from the application. */ extensionMinutes?: number; } /** * Session extension cost information */ export declare interface ExtensionCost { /** Token cost for the extension */ cost: number; /** Number of minutes to be added */ durationMinutes: number; /** Currency unit label */ unit: string; } /** * Extension cost response from GET /sdk/sessions/{session_id}/extension-cost */ export declare interface ExtensionCostResult { /** Number of minutes the session will be extended by */ extensionMinutes: number; /** Token cost for the extension */ tokenCost: number; /** ISO 8601 timestamp of the new expiry if extended */ newExpiresAt: string; /** Minimum allowed extension minutes (default: 15) */ minExtensionMinutes: number; /** Maximum allowed extension minutes (default: 480) */ maxExtensionMinutes: number; } /** * Extension Modal with duration slider for selecting extension time. * DOM-based component (no React dependency) for maximum compatibility. */ export declare class ExtensionModal { private modal; private theme; private themeMode; private legacyStyles; private slider; private currentCost; private debounceTimer; private keydownHandler; private previousActiveElement; constructor(themeMode?: ThemeMode, customStyles?: Partial); private detectDarkMode; /** * Show the extension modal with duration slider. */ show(options: ExtensionModalOptions): void; /** * Handle slider value changes with debounced cost updates. */ private handleSliderChange; /** * Update the cost display in the modal. */ private updateCostDisplay; private attachButtonListeners; private setLoadingState; /** * Hide and remove the modal from the DOM. */ hide(): void; /** * Check if the modal is currently shown. */ isShown(): boolean; } export declare interface ExtensionModalOptions { /** Current token balance */ currentBalance: number; /** Initial extension cost result (includes min/max) */ initialCost: ExtensionCostResult; /** Callback to fetch updated cost when slider changes */ onCostUpdate: (minutes: number) => Promise; /** Called when the user confirms the extension */ onConfirm: (extensionMinutes: number) => Promise; /** Called when the user cancels */ onCancel?: () => void; } /** * Extract JWT token from URL parameter * @param paramName - URL parameter name (default: 'gwSession') * @param url - URL to extract from (default: window.location.href) * @returns JWT token or null if not found */ export declare function extractTokenFromURL(paramName?: string, url?: string): string | null; /** * Idle-fade configuration for the floating session-controls widget. * Correctness invariant: fade never applies while the session is at or below its * warning threshold, regardless of these settings. */ export declare interface FadeConfig { /** Enable fade-to-idle behavior. Default: true */ enabled?: boolean; /** Opacity when idle, between 0 and 1. Default: 0.7 */ idleOpacity?: number; /** Milliseconds of inactivity before fading to idle opacity. Default: 5000 */ idleDelayMs?: number; } /** * Generate CSS string from theme colors for inline styles */ export declare function generateCSSVariables(theme: Theme): string; /** * Emit the session-controls CSS custom properties. * * The widget reads every visual value from `--gw-sc-*` variables so host * stylesheets can override any value via the cascade without requiring a * JavaScript config change. * * Returns a map of variable names to values. Callers spread the result into * inline styles or build a CSS string via `toCssVarString()`. */ export declare function generateSessionControlsVars(theme: Theme, extras?: { borderRadius?: string; shadow?: string; zIndex?: number; }): Record; /** * Get the configuration for a specific environment * * @param environment - The target environment * @returns Environment-specific configuration * * @example * ```typescript * const demoConfig = getEnvironmentConfig('demo'); * console.log(demoConfig.apiEndpoint); // 'https://demo-api.generalwisdom.com' * ``` */ export declare function getEnvironmentConfig(environment: Environment): EnvironmentConfig; /** * Get theme based on user preference or system setting */ export declare function getTheme(prefersDark?: boolean): Theme; /** References a named grant required for access. */ declare interface GrantRef { name: string; } /** * Heartbeat Manager for active session tracking * Phase 2 Feature - Sends periodic heartbeats to backend */ export declare class HeartbeatManager { private sessionId; private apiEndpoint; private token; private applicationId; private onSync?; private onError?; private intervalId; private heartbeatInterval; private failureCount; private maxFailures; private isEnabled; private logger; constructor(sessionId: string, apiEndpoint: string, token: string, applicationId: string | null, onSync?: ((remainingSeconds: number) => void) | undefined, onError?: ((error: Error) => void) | undefined, heartbeatIntervalSeconds?: number, debug?: boolean); /** * Start sending heartbeats */ start(): void; /** * Stop sending heartbeats */ stop(): void; /** * Send a single heartbeat to backend */ private sendHeartbeat; /** * Check if heartbeat is running */ isRunning(): boolean; /** * Get failure count */ getFailureCount(): number; /** * Update heartbeat interval */ updateInterval(seconds: number): void; } /** * Check if code is running in browser environment */ export declare function isBrowser(): boolean; /** * JWKS Key */ export declare interface JWKSKey { kty: string; use: string; kid: string; alg: string; n: string; e: string; } /** * JWKS Response */ export declare interface JWKSResponse { keys: JWKSKey[]; } /** * JWKS Validator for RS256 JWT signature verification * Uses jose library for browser and Node.js compatibility */ export declare class JWKSValidator { private jwksUri; private logger; private jwks; constructor(jwksUri: string, debug?: boolean); /** * Verify JWT signature using JWKS public key * @param token - JWT token to verify * @param expectedIssuer - Expected issuer (default: 'generalwisdom.com') * @param expectedApplicationId - Optional application ID to validate * @returns Decoded and verified JWT claims */ verify(token: string, expectedIssuer?: string, expectedApplicationId?: string): Promise; /** * Update JWKS URI * @param jwksUri - New JWKS URI */ updateJwksUri(jwksUri: string): void; } /** * JWT Claims (raw payload from token) */ export declare interface JWTClaims { sessionId: string; applicationId: string; userId: string; orgId: string; startTime: number; durationMinutes: number; iat: number; exp: number; iss: string; sub: string; } /** * JWT Header */ export declare interface JWTHeader { alg: string; typ: string; kid: string; } /** * JWT Parser for client-side token decoding * Note: Does NOT verify signature - use JWKSValidator for verification */ export declare class JWTParser { /** * Decode JWT payload without verification * @param token - JWT token string * @returns Decoded payload */ static decode(token: string): JWTClaims; /** * Decode JWT header * @param token - JWT token string * @returns Decoded header */ static decodeHeader(token: string): JWTHeader; /** * Extract specific claim from JWT * @param token - JWT token string * @param claim - Claim name to extract * @returns Claim value */ static extractClaim(token: string, claim: string): T; /** * Check if JWT is expired (client-side only, not authoritative) * @param token - JWT token string * @returns True if token is expired */ static isExpired(token: string): boolean; /** * Get time remaining until expiration * @param token - JWT token string * @returns Seconds remaining (0 if expired) */ static getTimeRemaining(token: string): number; /** * Base64 URL decode * @param str - Base64 URL encoded string * @returns Decoded string */ private static base64UrlDecode; } export declare interface KeywordItem { keyword: string; count: number; } export declare interface KeywordsResponse { keywords: KeywordItem[]; total: number; } /** Legacy options — unchanged from the original API. */ export declare interface LegacySessionHeaderOptions { getTime: () => string; sdk?: MarketplaceSDK; onEnd?: () => void; position?: "left" | "center" | "right"; } /** * Light theme matching gw-spa design system */ export declare const lightTheme: Theme; /** * Simple logger with debug mode support */ export declare class Logger { private debug; private prefix; constructor(debug?: boolean, prefix?: string); /** * Log debug message (only if debug enabled) */ log(...args: unknown[]): void; /** * Log info message (only if debug enabled) */ info(...args: unknown[]): void; /** * Log warning message (always shown) */ warn(...args: unknown[]): void; /** * Log error message (always shown) */ error(...args: unknown[]): void; } /** * Typed data payload for an application catalog item returned by marketplace search. * * Field names match the Go JSON tags in gw-go-common/models/application.go. * Use this interface when `MarketplaceSearchResult.resultType === "application"` to * access `minimumPrivyLevel` and other catalog fields in a type-safe way. * * An index signature is included so that unknown fields returned by future API * versions do not cause a TypeScript error. */ export declare interface MarketplaceApplicationData { /** Display name of the application */ name?: string; /** Short description */ description?: string; /** Application category */ category?: string; /** Publisher / organization name */ publisherName?: string; /** Base session price in SMART tokens */ basePrice?: number; /** Thumbnail image URL */ thumbnailUrl?: string; /** * Minimum Privy level required to launch a session for this application. * 0 means no Privy requirement; 1 means Privy 1 is required. * When > 0, item cards should display a PrivyBadge. * * Matches Go model: MinimumPrivyLevel int `json:"minimumPrivyLevel"` * * @deprecated Use audience.grants instead */ minimumPrivyLevel?: number; /** Defines visibility and access restrictions for this application */ audience?: Audience; /** Whether the application is currently active */ isActive?: boolean; /** Additional metadata fields */ [key: string]: unknown; } export declare interface MarketplaceApplicationResult extends MarketplaceSearchResultBase { resultType: "application"; /** @deprecated Use `resultType` — the `type` field is kept for backward compatibility */ type: "application"; data: MarketplaceApplicationData; } /** * Typed data payload for a dataset catalog item returned by marketplace search. * * Field names match the Go JSON tags in gw-go-common/models/dataset.go. * Use this interface when `MarketplaceSearchResult.resultType === "dataset"` to * access dataset-specific fields in a type-safe way. * * An index signature is included so that unknown fields returned by future API * versions do not cause a TypeScript error. */ export declare interface MarketplaceDatasetData { /** Display name of the dataset */ name?: string; /** Short description */ description?: string; /** Publisher / organization name */ publisherName?: string; /** Thumbnail / icon image URL */ iconUrl?: string; /** * Minimum Privy level required to query this dataset. * 0 means no Privy requirement; 1 means Privy 1 is required. * When > 0, item cards should display a PrivyBadge. * * Matches Go model: MinimumPrivyLevel int `json:"minimumPrivyLevel"` * * @deprecated Use audience.grants instead */ minimumPrivyLevel?: number; /** Defines visibility and access restrictions for this dataset */ audience?: Audience; /** Dataset visibility: "public" | "private" | "org" */ visibility?: string; /** Dataset status: "active" | "inactive" | "archived" */ status?: string; /** Additional metadata fields */ [key: string]: unknown; } export declare interface MarketplaceDatasetResult extends MarketplaceSearchResultBase { resultType: "dataset"; /** @deprecated Use `resultType` — the `type` field is kept for backward compatibility */ type: "dataset"; data: MarketplaceDatasetData; } /** * Marketplace SDK with Phase 2 Features * - Heartbeat system * - Multi-tab synchronization * - Visibility API integration * - Session extension/completion * - Backend validation */ declare class MarketplaceSDK { /** sessionStorage key used to persist the session JWT across navigations */ private static readonly JWT_STORAGE_KEY; /** Singleton instance used by React hooks */ private static _instance; /** * Return the current singleton SDK instance. * Throws if no instance has been created yet — callers must call * `new MarketplaceSDK(config)` before using hooks. */ static getInstance(): MarketplaceSDK; private config; private validator; private timer; private heartbeat; private tabSync; private modal; private purchaseModal; private logger; private events; private sessionData; private jwtToken; private apiKey; private endReason; /** Auto-mounted session-controls widget (GW-5294). Null when not mounted. */ private sessionHeaderInstance; constructor(config: SDKConfig); /** * Register event handlers */ on(event: K, handler: SDKEvents[K]): void; /** * Execute a lifecycle hook with timeout */ private executeHook; /** * Calculate actual session duration in minutes */ private calculateActualDuration; /** * Retrieve the session JWT from the URL or sessionStorage, guarding * against corrupted storage values (GW-8643). * * A prior page load may have persisted the literal string "undefined" * (or "null", or an empty/non-JWT string) under the storage key. Such * values are treated as absent and evicted so they can never reach * JWKS verification and fail with a cryptic "Invalid Compact JWS". */ private resolveSessionToken; /** * Persist the session JWT for navigation/OAuth-redirect persistence. * Never writes nullish or non-JWT values (GW-8643). */ private persistSessionToken; /** * Initialize SDK and validate session. * * Returns the validated {@link SessionData} when a session JWT is present. * * When no session token exists (no `?gwSession=` URL parameter and nothing * valid in sessionStorage) the SDK enters a "waiting for session" state * instead of throwing: it phones home so the platform setup page can show * "Connected", fires the optional `onWaitingForSession` event, and * resolves with `null`. It does NOT surface a JWT-verification error * (GW-8643). */ initialize(): Promise; /** * Phase 2: Validate JWT with backend */ private validateWithBackend; /** * Phase 2: Handle tab sync messages */ private handleTabSyncMessage; /** * Phase 2: Initialize Visibility API handling */ private initializeVisibilityHandling; /** * Start session timer manually */ startTimer(): void; /** * Pause session timer */ pauseTimer(): void; /** * Resume session timer */ resumeTimer(): void; /** * Get the cost and preview for extending the current session. * Calls GET /sdk/sessions/{session_id}/extension-cost * * @param extensionMinutes - Optional desired extension duration to preview cost for */ getExtensionCost(extensionMinutes?: number): Promise; /** * Extend the current session. * * Without skipConfirmation (default): shows PurchaseModal if available, * otherwise falls back to the onExtend callback. * * With skipConfirmation: calls POST /sdk/sessions/{session_id}/extend directly * and emits onPurchaseStart / onPurchaseSuccess or onPurchaseError events. */ extendSession(options?: ExtendSessionOptions): Promise; /** * Generate a UUID v4 idempotency key using the Web Crypto API (or Node crypto). */ private generateIdempotencyKey; /** * Phase 2: Complete session */ completeSession(_actualUsageMinutes?: number): Promise; /** * End session */ endSession(): Promise; /** * Show warning modal */ private showWarningModal; /** * Get current session data */ getSessionData(): SessionData | null; /** * Get remaining time */ getRemainingTime(): number; /** * Get formatted time (MM:SS) */ getFormattedTime(): string; /** * Get formatted time with hours (HH:MM:SS) */ getFormattedTimeWithHours(): string; /** * Check if timer is running */ isTimerRunning(): boolean; /** * Auto-mount the default session-controls widget when the developer has * not opted out. Called from `initialize()` after a successful session * start. Inline mode is mounted as well if explicitly requested. */ private maybeAutoMountSessionHeader; /** * Manually mount the session-controls widget. Useful when `autoMount` is * false and the developer wants to control mount timing. */ mountSessionHeader(opts: SessionHeaderMountOptions): void; /** Unmount and drop the auto-mounted session-controls widget, if any. */ unmountSessionHeader(): void; /** * Replace the mounted widget with new config. Unmounts the current * instance and remounts using the same runtime hooks (getTime, sdk, * onEnd). Intended for runtime updates to position, fade, links, etc. * * Remount is driven by whether the widget is currently mounted, not by * the resolved `autoMount` flag. `autoMount: false` means "don't mount * me during initialize()" — it doesn't mean "refuse to remount after * an explicit mountSessionHeader() call". Publishers who set * `autoMount: false` and drive the widget themselves must still be * able to update its config without it vanishing. * * The exception: if the caller passes `autoMount: false` in the * `partial` argument, treat that as an explicit unmount request. */ updateSessionControls(partial: Partial): void; /** * Returns the Authorization header value for authenticated API calls. * Uses the API key when available, otherwise falls back to the session JWT. * Throws if neither is available (SDK not initialized). */ private requireAuthHeader; /** * Build the standard headers object for all authenticated API calls. * Includes Authorization and Content-Type. When API-key authentication is * active and an applicationId is configured, adds the X-Application-Id header * so the backend authorizer can verify application ownership. */ /** * Notifies the platform that the SDK has successfully initialized. * Writes a telemetry record that the setup page connection poller reads. * Fires both after session validation AND when initialize() runs without * a session (waiting-for-session state), so the setup page can show * "Connected" before the first session (GW-8643). * Fire-and-forget — never blocks or throws to the caller. */ private phoneHome; private buildHeaders; /** * Returns the active session ID. * Throws if no session is active (SDK not initialized). */ private get sessionId(); /** * Fetch purchasable items for the active session. * Returns only items where status=active AND visibility=visible. * * GET /sdk/sessions/{session_id}/available-items */ getAvailableItems(): Promise; /** * Get the current SMART token balance for the active session user. * * GET /sdk/sessions/{session_id}/balance */ getTokenBalance(): Promise; /** * Map backend response to SDK ValidationResult. * Backend response shape from gw-sdk-api ValidatePurchaseResponse (main.go:406-411). * Returns { valid, reason, totalCost, remainingBalance } (already camelCase). */ private mapValidationResult; /** * Pre-validate a proposed purchase without committing it. * Surfaces balance, item status, and near-expiry warnings before showing a confirm UI. * * POST /sdk/sessions/{session_id}/purchases/validate */ validatePurchase(itemId: string, quantity?: number): Promise; /** * Execute an in-session purchase atomically. * Deducts tokens and records the purchase in a single DynamoDB transaction. * Use the idempotencyKey to safely retry failed requests. * * POST /sdk/sessions/{session_id}/purchases */ purchase(request: PurchaseRequest): Promise; /** * Trigger a purchase modal for any active item (including hidden items). * This method bypasses the add-ons panel and opens the PurchaseModal directly. * Used by publishers to trigger purchases from their own UI elements. * * @param itemId - The ID of the item to purchase * @throws {SDKError} If no active session exists */ requestPurchase(itemId: string): Promise; /** * Fetch the list of purchasable items for the current session. * * GET /sdk/sessions/{session_id}/items */ getItems(): Promise; /** * Retrieve the purchase history for the active session. * * GET /sdk/sessions/{session_id}/purchases */ getPurchaseHistory(): Promise; /** * Cleanup and destroy SDK instance */ destroy(): void; } export { MarketplaceSDK } export default MarketplaceSDK; export declare interface MarketplaceSearchEnrichRequest { searchRequestId: string; resultIds: string[]; query: string; } export declare interface MarketplaceSearchEnrichResponse { searchRequestId: string; enrichedResults: EnrichedResult[]; suggestions: string[]; } /** * Marketplace Search Types for Publisher SDK * * Types for the public marketplace search API endpoints. * These endpoints do NOT require authentication. */ export declare interface MarketplaceSearchRequest { query: string; categories?: ("application" | "dataset")[]; itemTypes?: ("application" | "dataset")[]; limit?: number; cursor?: string; sortBy?: "relevance" | "trending" | "popular" | "newest"; } export declare interface MarketplaceSearchResponse { results: MarketplaceSearchResult[]; suggestions: string[]; totalResults: number; query: string; searchRequestId: string; cursor?: string; hasMore: boolean; } export declare type MarketplaceSearchResult = MarketplaceApplicationResult | MarketplaceDatasetResult; /** Common fields shared by both application and dataset search results. */ declare interface MarketplaceSearchResultBase { id: string; relevanceScore: number; matchReason: string | null; trendingScore: number; popularScore: number; isPromoted: boolean; } export declare interface MarketplaceSearchSuggestionsResponse { suggestions: string[]; totalTracked: number; } /** * Merge a partial theme-token override onto a resolved base theme. * Used by SessionControlsConfig.theme to let developers override specific * colors or layout values without replacing the whole theme. * * Only fields present in the overrides object are applied; undefined fields * in nested objects are skipped so consumers may pass `{ colors: { primary } }` * and preserve every other color. */ export declare function mergeThemeTokens(base: Theme, overrides?: { colors?: Partial; borderRadius?: string | number; shadow?: string; }): Theme & { shadow?: string; borderRadiusOverride?: string; }; /** * Modal styling options (Legacy - prefer using theme) * @deprecated Use theme configuration from src/styles/theme.ts instead */ export declare interface ModalStyles { backgroundColor: string; textColor: string; primaryColor: string; borderRadius: string; fontFamily: string; } /** * Viewport-anchor position for the floating session-controls widget. * Six possible values combining vertical and horizontal edges. */ export declare type Position = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right"; /** * PrivyBadge renders an inline "Privy 1" badge to indicate that an item * requires Privy 1 verification before it can be purchased. * * DOM-based (no React dependency) for maximum compatibility. * Use `render()` to get an HTMLElement suitable for embedding in item cards, * or `renderHTML()` to get a raw HTML string for innerHTML injection. * * @example * ```ts * const badge = new PrivyBadge('light'); * itemCardEl.appendChild(badge.render()); * ``` */ export declare class PrivyBadge { private theme; constructor(themeMode?: ThemeMode, customStyles?: Partial); private detectDarkMode; /** * Returns an HTMLSpanElement styled as the Privy 1 badge. */ render(): HTMLSpanElement; /** * Returns a self-contained HTML string for use with innerHTML. */ renderHTML(): string; private badgeCss; } /** * Error detail returned when a purchase is blocked by an insufficient Privy level. * Only `requiredLevel` is exposed to the publisher; raw eligibility data is NOT forwarded. */ export declare interface PrivyRequiredError { /** Always 'insufficient_privy_level' */ code: "insufficient_privy_level"; /** Human-readable message */ message: string; /** Current Privy level of the user (e.g. 0) */ currentLevel: number; /** Minimum Privy level required to purchase (e.g. 1) */ requiredLevel: number; } /** * PrivyRequiredModal is shown when a purchase attempt is blocked because * the user's Privy level is insufficient. * * It shows a clear explanation and a deep-link button to the GW Privy upgrade * flow. The raw `privyEligibility` payload from the API is intentionally NOT * forwarded to publishers — only `requiredLevel` and `currentLevel` are used * here. * * DOM-based (no React dependency) for maximum compatibility. */ export declare class PrivyRequiredModal { private modal; private theme; private legacyStyles; constructor(themeMode?: ThemeMode, customStyles?: Partial); private detectDarkMode; /** * Build the upgrade deep-link URL. */ static buildUpgradeUrl(gwBaseUrl?: string): string; /** * Show the PRIVY_REQUIRED modal. */ show(options: PrivyRequiredModalOptions): void; private attachListeners; /** * Hide and remove the modal from the DOM. */ hide(): void; /** * Check if the modal is currently shown. */ isShown(): boolean; } export declare interface PrivyRequiredModalOptions { /** * The minimum Privy level required (typically 1). */ requiredLevel: number; /** * The user's current Privy level (typically 0 when this modal is shown). */ currentLevel: number; /** * Base URL of the GW platform. * Upgrade deep-link is constructed as `${gwBaseUrl}/settings?privy=upgrade`. * Defaults to `https://platform.generalwisdom.com`. */ gwBaseUrl?: string; /** * Called when the user clicks "Upgrade to Privy 1". * If omitted the modal opens the deep-link in a new tab and closes itself. */ onUpgrade?: (upgradeUrl: string) => void; /** * Called when the user dismisses the modal without upgrading. */ onCancel?: () => void; } /** * Purchase state constants. * Use these to handle distinct purchase outcomes in your UI. * * - INSUFFICIENT_FUNDS: user's token balance is too low * - PRIVY_REQUIRED: item requires Privy 1 verification; surface upgrade flow */ export declare const PURCHASE_STATE: { readonly INSUFFICIENT_FUNDS: "INSUFFICIENT_FUNDS"; readonly PRIVY_REQUIRED: "PRIVY_REQUIRED"; }; /** * Error detail returned when a purchase fails. */ export declare interface PurchaseError { /** Machine-readable error code */ code: PurchaseErrorCode; /** Human-readable message */ message: string; /** Item ID that the purchase failed for */ itemId: string; /** Current balance (present for insufficient_balance errors) */ currentBalance?: number; /** Item cost (present for insufficient_balance errors) */ itemCost?: number; } /** * In-Session Purchase Types for Marketplace SDK * * Types for the purchase API endpoints within an active session. * All purchase operations require a valid session JWT. * * Per PRP-044: In-Session Purchases */ /** * Discriminated union of all purchase error codes */ export declare type PurchaseErrorCode = "insufficient_balance" | "price_changed" | "session_expired" | "item_not_found" | "item_inactive" | "self_purchase_blocked" | "duplicate_purchase" | "rate_limited" | "validation_failed" | "insufficient_privy_level"; export declare interface PurchaseItem { /** Item identifier */ id: string; /** Display name for the item */ name: string; /** Token cost per unit */ tokenCost: number; } /** * Purchase Modal for publisher-triggered in-session purchases. * DOM-based component (no React dependency) for maximum compatibility. */ export declare class PurchaseModal { private modal; private theme; private legacyStyles; constructor(themeMode?: ThemeMode, customStyles?: Partial); private detectDarkMode; /** * Show the purchase confirmation modal. */ show(options: PurchaseModalOptions): void; private attachButtonListeners; private setLoadingState; /** * Show a purchase success notification briefly before hiding. */ showSuccess(result: PurchaseResult, durationMs?: number): void; /** * Hide and remove the modal from the DOM. */ hide(): void; /** * Check if the modal is currently shown. */ isShown(): boolean; private escapeHtml; } export declare interface PurchaseModalOptions { /** Item to purchase */ item: PurchaseItem; /** Quantity to purchase (default: 1) */ quantity?: number; /** Current token balance to display */ currentBalance: number; /** Called when the user confirms the purchase */ onConfirm: (quantity: number) => Promise; /** Called when the user cancels */ onCancel?: () => void; } /** * Request body for creating an in-session purchase. */ export declare interface PurchaseRequest { /** ID of the item to purchase */ itemId: string; /** Number of units to purchase (default 1, range 1–1000) */ quantity?: number; /** Client-generated UUIDv4 for idempotency */ idempotencyKey: string; /** Expected unit price (in tokens) — rejects if server price has changed */ expectedUnitPrice: number; } /** * Successful purchase confirmation returned by the API. */ export declare interface PurchaseResult { /** Unique purchase identifier */ purchaseId: string; /** Item that was purchased */ itemId: string; /** Item display name at purchase time */ itemName: string; /** Number of units purchased */ quantity: number; /** Total tokens deducted (quantity × unit price) */ totalTokenCost: number; /** Organization token balance after the deduction */ remainingBalance: number; /** ISO 8601 timestamp of purchase */ purchasedAt: string; /** Always 'completed' on success */ status: "completed"; } export declare type PurchaseState = (typeof PURCHASE_STATE)[keyof typeof PURCHASE_STATE]; /** * SDK Configuration */ export declare interface SDKConfig { /** Target environment ('production' or 'demo'). Sets environment-specific defaults. */ environment?: Environment; /** JWKS endpoint URL (default: https://api.generalwisdom.com/.well-known/jwks.json) */ jwksUri?: string; /** SDK API endpoint for all backend operations. Defaults to sdk.{env}.generalwisdom.com when environment is set. */ apiEndpoint?: string; /** Enable debug logging */ debug?: boolean; /** Auto-start timer after initialization */ autoStart?: boolean; /** Warning threshold in seconds (default: 300 = 5 minutes) */ warningThresholdSeconds?: number; /** Custom styling for warning modal (Legacy - prefer using themeMode) */ customStyles?: Partial; /** Theme mode for modal styling (default: 'light') */ themeMode?: ThemeMode; /** Application ID for validation */ applicationId?: string; /** Marketplace URL for redirects (default: https://d3p2yqofgy75sz.cloudfront.net/) */ marketplaceUrl?: string; /** Organization API key (format: gwsk_<64hex>). When provided, used as the Bearer token for all API calls except validateWithBackend. */ apiKey?: string; /** Enable heartbeat system (default: false) */ enableHeartbeat?: boolean; /** Heartbeat interval in seconds (default: 30) */ heartbeatIntervalSeconds?: number; /** Enable multi-tab synchronization (default: false) */ enableTabSync?: boolean; /** Pause timer when tab is hidden (default: false) */ pauseOnHidden?: boolean; /** Use backend validation instead of JWKS (default: false) */ useBackendValidation?: boolean; /** Optional hooks for synchronizing app auth state with marketplace sessions */ hooks?: SessionLifecycleHooks; /** Hook execution timeout in milliseconds (default: 5000) */ hookTimeoutMs?: number; /** Configuration for the default session-controls widget (GW-5294) */ sessionControls?: SessionControlsConfig; } /** * Custom SDK Error */ export declare class SDKError extends Error { code: string; statusCode?: number | undefined; constructor(message: string, code: string, statusCode?: number | undefined); } /** * SDK Event Handlers */ export declare interface SDKEvents { /** Called when session successfully initialized */ onSessionStart: (data: SessionData) => void; /** * Called when initialize() completes without a session token (GW-8643). * The SDK is connected (it has phoned home) but no marketplace session is * active yet — e.g. the app was opened directly rather than launched from * the marketplace. initialize() resolves with null in this state. */ onWaitingForSession: () => void; /** Called when warning threshold reached */ onSessionWarning: (data: { remainingSeconds: number; }) => void; /** Called when session expires or is ended */ onSessionEnd: () => void; /** Called on any error */ onError: (error: Error) => void; /** Called when the user's SMART token balance changes */ onBalanceChange: (balance: TokenBalance) => void; /** Called when a session extension completes successfully */ onSessionExtended: (data: { additionalMinutes: number; newExpiresAt: number; }) => void; /** Called when a purchase is initiated (including requestPurchase) */ onPurchaseStart: (data: { itemId: string; quantity: number; }) => void; /** Called when a purchase API call completes successfully */ onPurchaseSuccess: (result: PurchaseResult) => void; /** Called when a purchase API call fails */ onPurchaseError: (error: PurchaseError) => void; /** Called when a requestPurchase completes successfully (after modal confirm) */ onPurchaseComplete: (itemId: string) => void; /** Called when a requestPurchase is cancelled (user dismisses modal) */ onPurchaseCancelled: (itemId: string) => void; /** Called when balance changes (after any balance-changing operation) */ onBalanceUpdate: (balance: number) => void; } /** * A link rendered by the session-controls widget. * Links are href-only; onClick handlers are not supported. */ export declare interface SessionControlLink { /** Visible label */ label: string; /** Destination URL. External URLs open in a new tab with rel="noopener". */ href: string; /** Promote this link out of the overflow menu to the widget's top level. * A maximum of two links may be promoted; excess promotions fall back into overflow. */ primary?: boolean; /** Optional icon. Accepts an emoji (e.g. "📄") or URL; rendered before the label. */ icon?: string; } /** * Configuration for the default session-controls widget (GW-5294). * When omitted from SDKConfig, the SDK auto-mounts a floating widget at bottom-right. */ export declare interface SessionControlsConfig { /** Auto-mount the widget on sdk.initialize(). Default: true */ autoMount?: boolean; /** Rendering mode. Default: 'floating' */ mode?: "floating" | "inline"; /** Required when mode is 'inline'. CSS selector or HTMLElement to mount into. */ target?: string | HTMLElement; /** Viewport position (floating mode only). Default: 'bottom-right' */ position?: Position; /** Pixel offset from the anchored viewport edge (floating mode only). Default: { x: 16, y: 16 } */ offset?: { x?: number; y?: number; }; /** Idle-fade behavior. Default: { enabled: true, idleOpacity: 0.7, idleDelayMs: 5000 } */ fade?: FadeConfig; /** Developer-supplied links. Rendered in an overflow menu; up to two with primary:true are promoted. */ links?: SessionControlLink[]; /** Timer display format. Default: 'countdown' */ timerFormat?: TimerFormat; /** Render the Extend button. Default: true */ showExtendButton?: boolean; /** Partial theme-token override merged on top of the resolved light/dark theme. */ theme?: Partial; /** Stacking context override. Default: 2147483000 */ zIndex?: number; } /** * Session Data extracted from JWT */ export declare interface SessionData { /** Unique session UUID */ sessionId: string; /** Application ID */ applicationId: string; /** User ID */ userId: string; /** Organization ID */ orgId: string; /** Session start time (Unix timestamp seconds) */ startTime: number; /** Session duration in minutes */ durationMinutes: number; /** Issued at timestamp (Unix seconds) */ iat: number; /** Expiration timestamp (Unix seconds) */ exp: number; /** Issuer */ iss: string; /** Subject (user ID) */ sub: string; } export declare interface SessionEndContext { /** Unique session UUID */ sessionId: string; /** User ID */ userId: string; /** Reason for session end */ reason: "expired" | "manual" | "error"; /** Actual session duration in minutes (if available) */ actualDurationMinutes?: number; } export declare interface SessionExtendContext { /** Unique session UUID */ sessionId: string; /** User ID */ userId: string; /** Additional minutes added to session */ additionalMinutes: number; /** New expiration timestamp (Unix seconds) */ newExpiresAt: number; } export declare class SessionHeader { private theme; private container; private updateInterval; private timeDisplay; private balanceDisplay; private getTimeCallback; private onEndCallback; private sdk; private purchaseModal; private mounted; private itemsPanel; private availableItems; private balanceChangeHandler; private sessionExtendedHandler; private floatingContainer; private floatingRoot; private floatingTimer; private floatingFade; private floatingOverflow; private floatingWarningThresholdSeconds; private floatingCurrentThreshold; private floatingSessionWarningHandler; private floatingSessionExtendedHandler; constructor(themeMode?: ThemeMode); private detectDarkMode; /** * Mount the session header. * * Two call signatures: * * // Legacy — renders inline into the developer's container. * mount(targetElement, { getTime, sdk?, onEnd?, position? }) * * // New — renders as a floating viewport widget or inline by mode. * mount({ mode, target?, getTime, sdk?, onEnd?, position?, fade?, links?, ... }) * * Backward compatibility is preserved by runtime detection: if the first * argument is an `HTMLElement` or `string`, we dispatch to the legacy * renderer with the existing API. Otherwise we treat it as the new options * object. */ mount(target: HTMLElement | string, options: LegacySessionHeaderOptions): void; mount(options: SessionHeaderMountOptions): void; private isLegacyCall; /** * New (GW-5294) mount path. Branches to floating or inline based on `mode`. */ private mountNew; private resolveFloatingPosition; private applyFloatingCssVars; private renderFloatingContents; private createDivider; private registerFloatingSdkEvents; /** * Parse the formatted time ("MM:SS" or "H:MM:SS") and compute the * current threshold state. Falls back to 'neutral' on parse failure. */ private computeThresholdFromTimer; private applyThresholdState; /** * Legacy inline mount. Do not change behavior here without updating the * SessionHeader unit tests, which assert specific DOM output. */ private mountLegacy; private openExtensionModal; private refreshBalance; private createAddonsButton; private toggleItemsPanel; private createItemsPanel; private openItemPurchaseModal; private updateBalanceDisplay; private startUpdating; unmount(): void; destroy(): void; isMounted(): boolean; updateTheme(themeMode: ThemeMode): void; } /** * Session Header Component * * Two render modes: * * 1. **Legacy inline** (unchanged backward-compat path): * `sessionHeader.mount(element | selector, { getTime, sdk?, onEnd?, position? })` * Renders the existing inline DOM with timer, balance, extend, Add-ons, * and end controls. Preserved to avoid breaking existing consumers. * * 2. **Floating widget** (new GW-5294 path used by SDK auto-mount): * `sessionHeader.mount({ mode: 'floating', ... })` * Renders the redesigned widget — viewport-positioned pill with timer, * threshold color shifts, extend button, developer-configured links in * an overflow menu, and idle-fade behavior. * * The `mount()` method detects which form is in use by whether the first * argument is a DOM element / selector (legacy) or an options object (new). * This keeps existing callers working without code changes. */ /** * Options for the new floating/inline mount path (GW-5294). * Accepts `mode: 'floating'` | `mode: 'inline'`. Inline mode in this path * delegates to the legacy renderer so there's one inline implementation. */ export declare interface SessionHeaderMountOptions { mode?: "floating" | "inline"; /** Required when mode === 'inline'. */ target?: HTMLElement | string; getTime: () => string; sdk?: MarketplaceSDK; onEnd?: () => void; /** Floating mode: viewport anchor. Inline mode: horizontal alignment. */ position?: Position | "left" | "center" | "right"; offset?: { x?: number; y?: number; }; fade?: FadeConfig; links?: SessionControlLink[]; timerFormat?: TimerFormat; showExtendButton?: boolean; theme?: ThemeTokens; zIndex?: number; /** Warning threshold in seconds (from SDKConfig). Default 300. */ warningThresholdSeconds?: number; } /** * Session Lifecycle Hooks * Optional callbacks that allow applications to synchronize their auth state with marketplace sessions */ export declare interface SessionLifecycleHooks { /** * Called after JWT validation succeeds but before session timer starts * Use to: Auto-login user to your app's auth system * Note: Hook failure will prevent session from starting */ onSessionStart?: (context: SessionStartContext) => Promise | void; /** * Called when session expires or is manually ended, before redirect * Use to: Force logout user from your app's auth system * Note: Hook failure will be logged but won't prevent session end */ onSessionEnd?: (context: SessionEndContext) => Promise | void; /** * Called when session extension succeeds * Use to: Refresh app auth tokens if needed */ onSessionExtend?: (context: SessionExtendContext) => Promise | void; /** * Called before session warning modal is shown * Use to: Prepare user for session expiration */ onSessionWarning?: (context: SessionWarningContext) => Promise | void; } /** * A purchase record from the session's purchase history. */ export declare interface SessionPurchase { /** Unique purchase identifier */ purchaseId: string; /** Session in which the purchase was made */ sessionId: string; /** Item that was purchased */ itemId: string; /** Item display name at purchase time (denormalized snapshot) */ itemName: string; /** Item description at purchase time (denormalized snapshot) */ itemDescription: string; /** Number of units purchased */ quantity: number; /** Token cost per unit at purchase time */ unitPrice: number; /** Total tokens charged (quantity × unitPrice) */ totalTokens: number; /** Purchase outcome */ status: "completed" | "failed"; /** ISO 8601 timestamp of purchase */ createdAt: string; } /** * Session Lifecycle Hook Contexts */ export declare interface SessionStartContext { /** Unique session UUID */ sessionId: string; /** User ID from JWT */ userId: string; /** User email (if available in JWT) */ email?: string; /** Organization ID */ orgId: string; /** Application ID */ applicationId: string; /** Session duration in minutes */ durationMinutes: number; /** Expiration timestamp (Unix seconds) */ expiresAt: number; /** Full JWT token for app use */ jwt: string; } export declare interface SessionWarningContext { /** Unique session UUID */ sessionId: string; /** User ID */ userId: string; /** Remaining seconds until expiration */ remainingSeconds: number; } /** * Tab Synchronization Manager * Phase 2 Feature - Syncs session state across multiple tabs */ export declare class TabSyncManager { private sessionId; private onMessage; private channel; private storageKey; private logger; private isMaster; constructor(sessionId: string, onMessage: (message: TabSyncMessage) => void, debug?: boolean); /** * Initialize sync mechanism */ private initialize; /** * Broadcast message to other tabs */ broadcast(type: TabSyncMessage["type"], data?: Partial): void; /** * Handle incoming message */ private handleMessage; /** * Handle storage event (fallback mechanism) */ private handleStorageEvent; /** * Elect this tab as master if appropriate * Master tab is responsible for heartbeats */ private electMaster; /** * Check if this tab is the master */ isMasterTab(): boolean; /** * Cleanup and destroy */ destroy(): void; } export declare interface TabSyncMessage { type: "timer_update" | "pause" | "resume" | "end"; sessionId: string; remainingSeconds?: number; timestamp: number; } export declare interface Theme { colors: ThemeColors; typography: ThemeTypography; spacing: ThemeSpacing; } /** * Theme configuration matching the General Wisdom SPA design system * Based on gw-spa/src/styles/globals.css and Tailwind CSS v4 */ export declare interface ThemeColors { background: string; foreground: string; card: string; cardForeground: string; popover: string; popoverForeground: string; primary: string; primaryForeground: string; secondary: string; secondaryForeground: string; muted: string; mutedForeground: string; accent: string; accentForeground: string; destructive: string; destructiveForeground: string; success: string; successForeground: string; border: string; input: string; ring: string; } /** * Theme mode for modal styling */ export declare type ThemeMode = "light" | "dark" | "auto"; export declare interface ThemeSpacing { borderRadius: { sm: string; md: string; lg: string; }; padding: { sm: string; md: string; lg: string; xl: string; }; gap: { sm: string; md: string; lg: string; }; } /** * Subset of theme tokens that may be overridden via SessionControlsConfig.theme. * Matches the shape of the Theme interface in src/styles/theme.ts but with all * fields optional so partial overrides are type-safe. */ export declare interface ThemeTokens { colors?: Partial<{ background: string; foreground: string; card: string; cardForeground: string; popover: string; popoverForeground: string; primary: string; primaryForeground: string; secondary: string; secondaryForeground: string; muted: string; mutedForeground: string; accent: string; accentForeground: string; destructive: string; destructiveForeground: string; success: string; successForeground: string; border: string; input: string; ring: string; }>; borderRadius?: string | number; shadow?: string; } export declare interface ThemeTypography { fontFamily: string; fontSize: { xs: string; sm: string; base: string; lg: string; xl: string; "2xl": string; }; fontWeight: { normal: string; medium: string; semibold: string; bold: string; }; lineHeight: { tight: string; normal: string; relaxed: string; }; } /** * Timer display format for the session-controls widget. */ export declare type TimerFormat = "countdown" | "elapsed" | "both"; /** * Timer Manager for session countdown */ export declare class TimerManager { private remainingSeconds; private intervalId; private warningThreshold; private warningShown; private logger; private events; constructor(durationSeconds: number, warningThresholdSeconds?: number, events?: Partial, debug?: boolean); /** * Start countdown timer */ start(): void; /** * Stop timer */ stop(): void; /** * Pause timer */ pause(): void; /** * Resume timer */ resume(): void; /** * Get remaining time in seconds */ getRemainingSeconds(): number; /** * Get formatted time string (MM:SS) */ getFormattedTime(): string; /** * Get formatted time string with hours (HH:MM:SS) */ getFormattedTimeWithHours(): string; /** * Check if timer is running */ isRunning(): boolean; /** * Check if warning has been shown */ hasWarningBeenShown(): boolean; /** * Update remaining time (useful for syncing with server) */ updateRemainingTime(seconds: number): void; } /** * Convert a var map from `generateSessionControlsVars` into a CSS declaration string. */ export declare function toCssVarString(vars: Record): string; /** * SMART token balance information */ export declare interface TokenBalance { /** Current SMART token balance */ balance: number; /** Currency unit label */ unit: string; } /** * Pre-flight validation result for a proposed purchase. * Use validatePurchase() before showing a confirm UI to surface issues early. */ export declare interface ValidationResult { /** Whether the purchase would succeed at this moment */ canPurchase: boolean; /** Human-readable reason when canPurchase is false */ reason?: string; /** Current organization token balance */ currentBalance: number; /** Token cost of the item */ itemCost: number; /** True when session has less than 2 minutes remaining */ nearExpiry?: boolean; } /** * Warning Modal for session expiration alerts */ export declare class WarningModal { private modal; private theme; private legacyStyles; private updateInterval; private timeDisplay; private startTime; private initialSeconds; private onEndCallback; constructor(themeMode?: ThemeMode, customStyles?: Partial); private detectDarkMode; /** * Show warning modal */ show(options: { remainingSeconds: number; onExtend?: () => void; onEnd?: () => void; }): void; /** * Hide and remove modal */ hide(): void; /** * Check if modal is currently shown */ isShown(): boolean; /** * GW-6674: Put the Extend button into a pending state while the async * extension request is in flight. Disables the button so the user can't * double-click and clears any prior inline error. No-op if the modal is gone. */ setExtendPending(): void; /** * GW-6674: Show an inline error inside the open warning modal when an * extension attempt fails, and re-enable the Extend button so the user can * retry. This replaces the previous behavior of redirecting the whole app * tab to the marketplace (which destroyed the user's in-progress work on any * extend failure). No-op if the modal is no longer shown. */ showError(message: string): void; /** * Show "Session Ending" modal before redirect * Displays for a fixed duration (3 seconds) then calls callback */ showEndingMessage(onComplete: () => void, durationMs?: number): void; } export { }