@mushi-mushi/core 1.23.0 → 1.25.0

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/index.d.cts CHANGED
@@ -1390,6 +1390,10 @@ interface MushiApiClient {
1390
1390
  postDiscoveryEvent(event: MushiDiscoveryEventPayload): Promise<MushiApiResponse<{
1391
1391
  accepted: boolean;
1392
1392
  }>>;
1393
+ /** POST /v1/sdk/session — lightweight session lifecycle event (best-effort). */
1394
+ postSessionEvent(payload: MushiSessionEventPayload): Promise<MushiApiResponse<{
1395
+ accepted: boolean;
1396
+ }>>;
1393
1397
  listReporterReports(reporterToken: string): Promise<MushiApiResponse<{
1394
1398
  reports: MushiReporterReport[];
1395
1399
  }>>;
@@ -1520,6 +1524,28 @@ interface MushiDiscoveryEventPayload {
1520
1524
  sdk_version?: string;
1521
1525
  observed_at: string;
1522
1526
  }
1527
+ /** Payload for /v1/sdk/session — lightweight session lifecycle tracking.
1528
+ * Best-effort, no offline queue. Privacy-safe: no PII by default;
1529
+ * `user_id_hash` is the same device-fingerprint hash used elsewhere. */
1530
+ interface MushiSessionEventPayload {
1531
+ /** Lifecycle event kind. */
1532
+ kind: 'session_start' | 'session_heartbeat' | 'session_end' | 'page_view';
1533
+ session_id: string;
1534
+ /** ISO timestamp of the event. */
1535
+ ts: string;
1536
+ /** Entry route for session_start; current route for page_view. */
1537
+ route?: string | null;
1538
+ /** document.referrer on session_start. */
1539
+ referrer?: string | null;
1540
+ /** Total page views in this session so far (updated on heartbeat/end). */
1541
+ page_view_count?: number;
1542
+ /** Device fingerprint hash — same token used in reports. */
1543
+ reporter_token_hash?: string | null;
1544
+ /** user_id_hash when the host app called Mushi.identify(). */
1545
+ user_id_hash?: string | null;
1546
+ user_agent?: string | null;
1547
+ sdk_version?: string;
1548
+ }
1523
1549
  interface MushiApiResponse<T> {
1524
1550
  ok: boolean;
1525
1551
  data?: T;
@@ -1932,6 +1958,48 @@ declare function getDeviceFingerprintHash(): Promise<string | null>;
1932
1958
 
1933
1959
  declare function getSessionId(): string;
1934
1960
 
1961
+ /**
1962
+ * FILE: packages/core/src/session-tracker.ts
1963
+ * PURPOSE: Lightweight session-lifecycle tracking for the Mushi SDK.
1964
+ *
1965
+ * Emits best-effort events to /v1/sdk/session so the console can show per-
1966
+ * project activity analytics (DAU/WAU, page views, identified vs. anonymous
1967
+ * user split, top routes). Mirrors the postDiscoveryEvent pattern: 1 retry,
1968
+ * no offline queue, fire-and-forget after visibility-change.
1969
+ *
1970
+ * Privacy:
1971
+ * - No PII by default. `reporter_token_hash` is the same opaque device
1972
+ * fingerprint already used in reports. `user_id_hash` is only set when
1973
+ * the host app calls Mushi.identify().
1974
+ * - Respects the SDK-level `trackSessions: false` opt-out option.
1975
+ * - Respects a DNT / Global Privacy Control header at the SDK init layer;
1976
+ * callers should check `shouldRespectDnt()` before calling `initSession`.
1977
+ */
1978
+
1979
+ interface SessionTrackerOptions {
1980
+ client: MushiApiClient;
1981
+ sdkVersion?: string;
1982
+ reporterTokenHash?: string | null;
1983
+ userIdHash?: string | null;
1984
+ }
1985
+ /**
1986
+ * Initialise the session tracker. Call once at SDK init for web environments.
1987
+ * Subsequent calls on the same page are no-ops (idempotent).
1988
+ *
1989
+ * Emits: session_start immediately, heartbeats every minute, session_end on
1990
+ * visibilitychange/pagehide, and page_view on history API navigation.
1991
+ */
1992
+ declare function initSessionTracker(opts: SessionTrackerOptions): void;
1993
+ /**
1994
+ * Record a page view manually — call from framework router hooks where the
1995
+ * history patch may fire too early (e.g. React Router v7 loader transitions).
1996
+ */
1997
+ declare function trackPageView(route?: string): void;
1998
+ /** Update the user identity after a Mushi.identify() call. */
1999
+ declare function updateSessionIdentity(userIdHash: string | null): void;
2000
+ /** Tear down timers (e.g. in tests or SSR environments). */
2001
+ declare function destroySessionTracker(): void;
2002
+
1935
2003
  interface RateLimiterConfig {
1936
2004
  maxBurst?: number;
1937
2005
  refillRate?: number;
@@ -2435,4 +2503,4 @@ declare function projectInitialsThemeIndex(projectId: string): number;
2435
2503
  */
2436
2504
  declare function readPageFaviconHref(): string | null;
2437
2505
 
2438
- export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, type EnvConfigDiagnostics, type EnvNearMiss, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type MushiBetaChangelogEntry, type MushiBetaModeConfig, type MushiBreadcrumb, type MushiCaptureConfig, type MushiCaptureEventInput, type MushiCaptureExceptionOptions, type MushiColorPalette, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiCrossAppReport, type MushiCustomCategory, type MushiDiagnosticsResult, type MushiDiscoverInventoryConfig, type MushiDiscoveryEventPayload, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiHallOfFameEntry, type MushiIdentityClaims, type MushiIntegrationsConfig, type MushiInternalRequestKind, type MushiLeaderboardEntry, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPageContext, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiPreset, type MushiPrivacyConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiReporterComment, type MushiReporterReport, type MushiReputationResult, type MushiRewardsConfig, type MushiRuntimeSdkConfig, type MushiSDKInstance, type MushiSdkVersionInfo, type MushiSelectedElement, type MushiSentryConfig, type MushiSentryContext, type MushiTesterReputation, type MushiThemeMode, type MushiTierResult, type MushiTimelineEntry, type MushiTimelineKind, type MushiTokenSnapshot, type MushiTracePropagationConfig, type MushiUrlMatcher, type MushiWidgetAnchor, type MushiWidgetConfig, type NormalisedException, type OfflineQueue, type PayloadGuardResult, type PiiScrubberConfig, type PreFilterResult, type ProjectFaviconSource, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, diagnoseEnvConfig, estimateJsonBytes, expandPreset, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, sha256Hex, validateConfig };
2506
+ export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, type EnvConfigDiagnostics, type EnvNearMiss, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type MushiBetaChangelogEntry, type MushiBetaModeConfig, type MushiBreadcrumb, type MushiCaptureConfig, type MushiCaptureEventInput, type MushiCaptureExceptionOptions, type MushiColorPalette, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiCrossAppReport, type MushiCustomCategory, type MushiDiagnosticsResult, type MushiDiscoverInventoryConfig, type MushiDiscoveryEventPayload, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiHallOfFameEntry, type MushiIdentityClaims, type MushiIntegrationsConfig, type MushiInternalRequestKind, type MushiLeaderboardEntry, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPageContext, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiPreset, type MushiPrivacyConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiReporterComment, type MushiReporterReport, type MushiReputationResult, type MushiRewardsConfig, type MushiRuntimeSdkConfig, type MushiSDKInstance, type MushiSdkVersionInfo, type MushiSelectedElement, type MushiSentryConfig, type MushiSentryContext, type MushiSessionEventPayload, type MushiTesterReputation, type MushiThemeMode, type MushiTierResult, type MushiTimelineEntry, type MushiTimelineKind, type MushiTokenSnapshot, type MushiTracePropagationConfig, type MushiUrlMatcher, type MushiWidgetAnchor, type MushiWidgetConfig, type NormalisedException, type OfflineQueue, type PayloadGuardResult, type PiiScrubberConfig, type PreFilterResult, type ProjectFaviconSource, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, type SessionTrackerOptions, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroySessionTracker, diagnoseEnvConfig, estimateJsonBytes, expandPreset, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initSessionTracker, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, sha256Hex, trackPageView, updateSessionIdentity, validateConfig };
package/dist/index.d.ts CHANGED
@@ -1390,6 +1390,10 @@ interface MushiApiClient {
1390
1390
  postDiscoveryEvent(event: MushiDiscoveryEventPayload): Promise<MushiApiResponse<{
1391
1391
  accepted: boolean;
1392
1392
  }>>;
1393
+ /** POST /v1/sdk/session — lightweight session lifecycle event (best-effort). */
1394
+ postSessionEvent(payload: MushiSessionEventPayload): Promise<MushiApiResponse<{
1395
+ accepted: boolean;
1396
+ }>>;
1393
1397
  listReporterReports(reporterToken: string): Promise<MushiApiResponse<{
1394
1398
  reports: MushiReporterReport[];
1395
1399
  }>>;
@@ -1520,6 +1524,28 @@ interface MushiDiscoveryEventPayload {
1520
1524
  sdk_version?: string;
1521
1525
  observed_at: string;
1522
1526
  }
1527
+ /** Payload for /v1/sdk/session — lightweight session lifecycle tracking.
1528
+ * Best-effort, no offline queue. Privacy-safe: no PII by default;
1529
+ * `user_id_hash` is the same device-fingerprint hash used elsewhere. */
1530
+ interface MushiSessionEventPayload {
1531
+ /** Lifecycle event kind. */
1532
+ kind: 'session_start' | 'session_heartbeat' | 'session_end' | 'page_view';
1533
+ session_id: string;
1534
+ /** ISO timestamp of the event. */
1535
+ ts: string;
1536
+ /** Entry route for session_start; current route for page_view. */
1537
+ route?: string | null;
1538
+ /** document.referrer on session_start. */
1539
+ referrer?: string | null;
1540
+ /** Total page views in this session so far (updated on heartbeat/end). */
1541
+ page_view_count?: number;
1542
+ /** Device fingerprint hash — same token used in reports. */
1543
+ reporter_token_hash?: string | null;
1544
+ /** user_id_hash when the host app called Mushi.identify(). */
1545
+ user_id_hash?: string | null;
1546
+ user_agent?: string | null;
1547
+ sdk_version?: string;
1548
+ }
1523
1549
  interface MushiApiResponse<T> {
1524
1550
  ok: boolean;
1525
1551
  data?: T;
@@ -1932,6 +1958,48 @@ declare function getDeviceFingerprintHash(): Promise<string | null>;
1932
1958
 
1933
1959
  declare function getSessionId(): string;
1934
1960
 
1961
+ /**
1962
+ * FILE: packages/core/src/session-tracker.ts
1963
+ * PURPOSE: Lightweight session-lifecycle tracking for the Mushi SDK.
1964
+ *
1965
+ * Emits best-effort events to /v1/sdk/session so the console can show per-
1966
+ * project activity analytics (DAU/WAU, page views, identified vs. anonymous
1967
+ * user split, top routes). Mirrors the postDiscoveryEvent pattern: 1 retry,
1968
+ * no offline queue, fire-and-forget after visibility-change.
1969
+ *
1970
+ * Privacy:
1971
+ * - No PII by default. `reporter_token_hash` is the same opaque device
1972
+ * fingerprint already used in reports. `user_id_hash` is only set when
1973
+ * the host app calls Mushi.identify().
1974
+ * - Respects the SDK-level `trackSessions: false` opt-out option.
1975
+ * - Respects a DNT / Global Privacy Control header at the SDK init layer;
1976
+ * callers should check `shouldRespectDnt()` before calling `initSession`.
1977
+ */
1978
+
1979
+ interface SessionTrackerOptions {
1980
+ client: MushiApiClient;
1981
+ sdkVersion?: string;
1982
+ reporterTokenHash?: string | null;
1983
+ userIdHash?: string | null;
1984
+ }
1985
+ /**
1986
+ * Initialise the session tracker. Call once at SDK init for web environments.
1987
+ * Subsequent calls on the same page are no-ops (idempotent).
1988
+ *
1989
+ * Emits: session_start immediately, heartbeats every minute, session_end on
1990
+ * visibilitychange/pagehide, and page_view on history API navigation.
1991
+ */
1992
+ declare function initSessionTracker(opts: SessionTrackerOptions): void;
1993
+ /**
1994
+ * Record a page view manually — call from framework router hooks where the
1995
+ * history patch may fire too early (e.g. React Router v7 loader transitions).
1996
+ */
1997
+ declare function trackPageView(route?: string): void;
1998
+ /** Update the user identity after a Mushi.identify() call. */
1999
+ declare function updateSessionIdentity(userIdHash: string | null): void;
2000
+ /** Tear down timers (e.g. in tests or SSR environments). */
2001
+ declare function destroySessionTracker(): void;
2002
+
1935
2003
  interface RateLimiterConfig {
1936
2004
  maxBurst?: number;
1937
2005
  refillRate?: number;
@@ -2435,4 +2503,4 @@ declare function projectInitialsThemeIndex(projectId: string): number;
2435
2503
  */
2436
2504
  declare function readPageFaviconHref(): string | null;
2437
2505
 
2438
- export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, type EnvConfigDiagnostics, type EnvNearMiss, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type MushiBetaChangelogEntry, type MushiBetaModeConfig, type MushiBreadcrumb, type MushiCaptureConfig, type MushiCaptureEventInput, type MushiCaptureExceptionOptions, type MushiColorPalette, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiCrossAppReport, type MushiCustomCategory, type MushiDiagnosticsResult, type MushiDiscoverInventoryConfig, type MushiDiscoveryEventPayload, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiHallOfFameEntry, type MushiIdentityClaims, type MushiIntegrationsConfig, type MushiInternalRequestKind, type MushiLeaderboardEntry, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPageContext, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiPreset, type MushiPrivacyConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiReporterComment, type MushiReporterReport, type MushiReputationResult, type MushiRewardsConfig, type MushiRuntimeSdkConfig, type MushiSDKInstance, type MushiSdkVersionInfo, type MushiSelectedElement, type MushiSentryConfig, type MushiSentryContext, type MushiTesterReputation, type MushiThemeMode, type MushiTierResult, type MushiTimelineEntry, type MushiTimelineKind, type MushiTokenSnapshot, type MushiTracePropagationConfig, type MushiUrlMatcher, type MushiWidgetAnchor, type MushiWidgetConfig, type NormalisedException, type OfflineQueue, type PayloadGuardResult, type PiiScrubberConfig, type PreFilterResult, type ProjectFaviconSource, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, diagnoseEnvConfig, estimateJsonBytes, expandPreset, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, sha256Hex, validateConfig };
2506
+ export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, type EnvConfigDiagnostics, type EnvNearMiss, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, type MushiActivityEvent, type MushiApiCascadeConfig, type MushiApiClient, type MushiApiResponse, type MushiAssistantConfig, type MushiAssistantReply, type MushiAssistantStep, type MushiBannerConfig, type MushiBannerLink, type MushiBetaChangelogEntry, type MushiBetaModeConfig, type MushiBreadcrumb, type MushiCaptureConfig, type MushiCaptureEventInput, type MushiCaptureExceptionOptions, type MushiColorPalette, type MushiConfig, type MushiConsoleEntry, type MushiCooldownConfig, type MushiCrossAppReport, type MushiCustomCategory, type MushiDiagnosticsResult, type MushiDiscoverInventoryConfig, type MushiDiscoveryEventPayload, type MushiEnvironment, type MushiEventHandler, type MushiEventType, type MushiHallOfFameEntry, type MushiIdentityClaims, type MushiIntegrationsConfig, type MushiInternalRequestKind, type MushiLeaderboardEntry, type MushiNetworkEntry, type MushiOfflineConfig, type MushiOnDeviceClassifier, type MushiOnDeviceClassifierInput, type MushiOnDeviceClassifierResult, type MushiPageContext, type MushiPerformanceMetrics, type MushiPreFilterConfig, type MushiPreset, type MushiPrivacyConfig, type MushiProactiveConfig, type MushiRegion, type MushiReport, type MushiReportBuilder, type MushiReportCategory, type MushiReportStatus, type MushiReporterComment, type MushiReporterReport, type MushiReputationResult, type MushiRewardsConfig, type MushiRuntimeSdkConfig, type MushiSDKInstance, type MushiSdkVersionInfo, type MushiSelectedElement, type MushiSentryConfig, type MushiSentryContext, type MushiSessionEventPayload, type MushiTesterReputation, type MushiThemeMode, type MushiTierResult, type MushiTimelineEntry, type MushiTimelineKind, type MushiTokenSnapshot, type MushiTracePropagationConfig, type MushiUrlMatcher, type MushiWidgetAnchor, type MushiWidgetConfig, type NormalisedException, type OfflineQueue, type PayloadGuardResult, type PiiScrubberConfig, type PreFilterResult, type ProjectFaviconSource, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, type SessionTrackerOptions, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroySessionTracker, diagnoseEnvConfig, estimateJsonBytes, expandPreset, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initSessionTracker, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, sha256Hex, trackPageView, updateSessionIdentity, validateConfig };
package/dist/index.js CHANGED
@@ -358,6 +358,17 @@ function createApiClient(options) {
358
358
  );
359
359
  },
360
360
  // ─── Rewards program (P1) ──────────────────────────────────
361
+ /** POST /v1/sdk/session — lightweight session lifecycle events.
362
+ * Best-effort (1 retry, no offline queue) — mirrors postDiscoveryEvent. */
363
+ async postSessionEvent(payload) {
364
+ return request(
365
+ "POST",
366
+ "/v1/sdk/session",
367
+ payload,
368
+ 1,
369
+ "discovery"
370
+ );
371
+ },
361
372
  async submitActivity(userId, events, opts) {
362
373
  return request(
363
374
  "POST",
@@ -1167,12 +1178,12 @@ function createOfflineQueue(config = {}) {
1167
1178
  const n = row.attempts;
1168
1179
  return typeof n === "number" && Number.isFinite(n) ? n : 0;
1169
1180
  }
1170
- function isExpired(row, now) {
1181
+ function isExpired(row, now2) {
1171
1182
  const queuedAt = row.queuedAt;
1172
1183
  if (!queuedAt) return false;
1173
1184
  const ts = Date.parse(queuedAt);
1174
1185
  if (Number.isNaN(ts)) return false;
1175
- return now - ts > MAX_QUEUE_AGE_MS;
1186
+ return now2 - ts > MAX_QUEUE_AGE_MS;
1176
1187
  }
1177
1188
  function detectBackend() {
1178
1189
  if (backendType) return backendType;
@@ -1351,10 +1362,10 @@ function createOfflineQueue(config = {}) {
1351
1362
  } else {
1352
1363
  rows = lsRead();
1353
1364
  }
1354
- const now = Date.now();
1365
+ const now2 = Date.now();
1355
1366
  const fresh = [];
1356
1367
  for (const row of rows) {
1357
- if (isExpired(row, now)) {
1368
+ if (isExpired(row, now2)) {
1358
1369
  const rowId = row.id;
1359
1370
  await removeRow(backend, rowId);
1360
1371
  queueLog.debug("Offline queue: evicting stale report", { id: rowId });
@@ -1819,6 +1830,111 @@ function randomSuffix() {
1819
1830
  return n.toString(36).padStart(6, "0").slice(0, 6);
1820
1831
  }
1821
1832
 
1833
+ // src/session-tracker.ts
1834
+ var HEARTBEAT_INTERVAL_MS = 6e4;
1835
+ var _client = null;
1836
+ var _sdkVersion;
1837
+ var _userIdHash = null;
1838
+ var _reporterTokenHash = null;
1839
+ var _pageViewCount = 0;
1840
+ var _heartbeatTimer = null;
1841
+ var _initialized = false;
1842
+ function now() {
1843
+ return (/* @__PURE__ */ new Date()).toISOString();
1844
+ }
1845
+ function currentRoute() {
1846
+ if (typeof window === "undefined") return "";
1847
+ return window.location.pathname + window.location.search;
1848
+ }
1849
+ function userAgent() {
1850
+ if (typeof navigator === "undefined") return null;
1851
+ return navigator.userAgent ?? null;
1852
+ }
1853
+ function buildPayload(kind, extra) {
1854
+ return {
1855
+ kind,
1856
+ session_id: getSessionId(),
1857
+ ts: now(),
1858
+ page_view_count: _pageViewCount,
1859
+ reporter_token_hash: _reporterTokenHash,
1860
+ user_id_hash: _userIdHash,
1861
+ user_agent: userAgent(),
1862
+ sdk_version: _sdkVersion,
1863
+ ...extra
1864
+ };
1865
+ }
1866
+ function send(payload) {
1867
+ if (!_client) return;
1868
+ _client.postSessionEvent(payload).catch(() => {
1869
+ });
1870
+ }
1871
+ function initSessionTracker(opts) {
1872
+ if (_initialized || typeof window === "undefined") return;
1873
+ _initialized = true;
1874
+ _client = opts.client;
1875
+ _sdkVersion = opts.sdkVersion;
1876
+ _reporterTokenHash = opts.reporterTokenHash ?? null;
1877
+ _userIdHash = opts.userIdHash ?? null;
1878
+ const entryRoute = currentRoute();
1879
+ _pageViewCount = 1;
1880
+ send(buildPayload("session_start", {
1881
+ route: entryRoute,
1882
+ referrer: typeof document !== "undefined" ? document.referrer ?? null : null
1883
+ }));
1884
+ _heartbeatTimer = setInterval(() => {
1885
+ send(buildPayload("session_heartbeat", { route: currentRoute() }));
1886
+ }, HEARTBEAT_INTERVAL_MS);
1887
+ const onHide = () => {
1888
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") {
1889
+ send(buildPayload("session_end", { route: currentRoute() }));
1890
+ }
1891
+ };
1892
+ if (typeof document !== "undefined") {
1893
+ document.addEventListener("visibilitychange", onHide, { passive: true });
1894
+ }
1895
+ if (typeof window !== "undefined") {
1896
+ window.addEventListener("pagehide", () => {
1897
+ send(buildPayload("session_end", { route: currentRoute() }));
1898
+ }, { passive: true });
1899
+ }
1900
+ patchHistoryForPageViews();
1901
+ }
1902
+ function trackPageView(route) {
1903
+ if (!_initialized || !_client) return;
1904
+ _pageViewCount += 1;
1905
+ send(buildPayload("page_view", { route: route ?? currentRoute() }));
1906
+ }
1907
+ function updateSessionIdentity(userIdHash) {
1908
+ _userIdHash = userIdHash;
1909
+ }
1910
+ function destroySessionTracker() {
1911
+ if (_heartbeatTimer != null) {
1912
+ clearInterval(_heartbeatTimer);
1913
+ _heartbeatTimer = null;
1914
+ }
1915
+ _initialized = false;
1916
+ _client = null;
1917
+ }
1918
+ var _historyPatched = false;
1919
+ function patchHistoryForPageViews() {
1920
+ if (_historyPatched || typeof history === "undefined") return;
1921
+ _historyPatched = true;
1922
+ const wrap = (original) => function(...args) {
1923
+ const result = original.apply(this, args);
1924
+ if (original === history.pushState) {
1925
+ _pageViewCount += 1;
1926
+ send(buildPayload("page_view", { route: currentRoute() }));
1927
+ }
1928
+ return result;
1929
+ };
1930
+ history.pushState = wrap(history.pushState);
1931
+ history.replaceState = wrap(history.replaceState);
1932
+ window.addEventListener("popstate", () => {
1933
+ _pageViewCount += 1;
1934
+ send(buildPayload("page_view", { route: currentRoute() }));
1935
+ }, { passive: true });
1936
+ }
1937
+
1822
1938
  // src/rate-limiter.ts
1823
1939
  var DEFAULT_MAX_BURST = 10;
1824
1940
  var DEFAULT_REFILL_RATE = 1;
@@ -1832,12 +1948,12 @@ function createRateLimiter(config = {}) {
1832
1948
  let tokens = maxBurst;
1833
1949
  let lastRefill = Date.now();
1834
1950
  function refill() {
1835
- const now = Date.now();
1836
- const elapsed = now - lastRefill;
1951
+ const now2 = Date.now();
1952
+ const elapsed = now2 - lastRefill;
1837
1953
  const refills = Math.floor(elapsed / refillIntervalMs);
1838
1954
  if (refills > 0) {
1839
1955
  tokens = Math.min(maxBurst, tokens + refills * refillRate);
1840
- lastRefill = now;
1956
+ lastRefill = now2;
1841
1957
  }
1842
1958
  }
1843
1959
  function tryConsume() {
@@ -2151,15 +2267,15 @@ function mushiTokens(mode) {
2151
2267
  // src/identity.ts
2152
2268
  var MUSHI_IDENTITY_TOKEN_PREFIX = "mushi.identity";
2153
2269
  function buildIdentityClaims(input) {
2154
- const now = Math.floor(Date.now() / 1e3);
2270
+ const now2 = Math.floor(Date.now() / 1e3);
2155
2271
  const ttl = input.ttlSeconds && input.ttlSeconds > 0 ? Math.min(input.ttlSeconds, 3600) : 600;
2156
2272
  return {
2157
2273
  projectId: input.projectId,
2158
2274
  sub: input.userId,
2159
2275
  ...input.email ? { email: input.email } : {},
2160
2276
  ...input.name ? { name: input.name } : {},
2161
- iat: now,
2162
- exp: now + ttl
2277
+ iat: now2,
2278
+ exp: now2 + ttl
2163
2279
  };
2164
2280
  }
2165
2281
  function base64UrlDecode(segment) {
@@ -2198,12 +2314,12 @@ var MULTI_TENANT_PARENT_HOSTS = /* @__PURE__ */ new Set(["kensaur.us", "www.kens
2198
2314
  var SLUG_DOMAIN_HINTS = {
2199
2315
  "glot-it": "glot.it",
2200
2316
  glotit: "glot.it",
2201
- "solo-boss-cloud": "sbc-front.vercel.app",
2317
+ "solo-boss-cloud": "solo-boss.kensaur.us",
2202
2318
  "mushi-mushi": "kensaur.us"
2203
2319
  };
2204
2320
  var SLUG_ICON_URL_HINTS = {
2205
2321
  "mushi-mushi": "https://kensaur.us/mushi-mushi/admin/favicon.svg",
2206
- "solo-boss-cloud": "https://sbc-front.vercel.app/favicon.svg",
2322
+ "solo-boss-cloud": "https://solo-boss.kensaur.us/favicon.svg",
2207
2323
  "glot-it": "https://kensaur.us/glot-it/apple-touch-icon.png",
2208
2324
  glotit: "https://kensaur.us/glot-it/apple-touch-icon.png"
2209
2325
  };
@@ -2377,6 +2493,6 @@ function isSafeFaviconHref(href) {
2377
2493
  }
2378
2494
  }
2379
2495
 
2380
- export { DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, REGION_ENDPOINTS, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, diagnoseEnvConfig, estimateJsonBytes, expandPreset, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, sha256Hex, validateConfig };
2496
+ export { DEFAULT_API_ENDPOINT, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_ACCENT_SHADOW, MUSHI_BANNER_BRAND_BORDER, MUSHI_BANNER_NEON, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_INVERSE, MUSHI_MOTION, MUSHI_ON_ACCENT, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_REPORTER_STATUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TIER_COLORS, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, REGION_ENDPOINTS, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, destroySessionTracker, diagnoseEnvConfig, estimateJsonBytes, expandPreset, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, hmacSha256Hex, initSessionTracker, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, resolveWidgetAccent, safeWidgetHex, scrubPii, sha256Hex, trackPageView, updateSessionIdentity, validateConfig };
2381
2497
  //# sourceMappingURL=index.js.map
2382
2498
  //# sourceMappingURL=index.js.map