@mushi-mushi/core 1.19.0 → 1.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1536,6 +1536,8 @@ interface MushiCrossAppReport {
1536
1536
  project_id: string | null;
1537
1537
  app_name: string | null;
1538
1538
  app_slug: string | null;
1539
+ /** Hostname from latest SDK heartbeat — used for favicon in cross-app list. */
1540
+ app_domain?: string | null;
1539
1541
  }
1540
1542
  /** A single entry in the global tester leaderboard. */
1541
1543
  interface MushiLeaderboardEntry {
@@ -1557,6 +1559,22 @@ interface MushiTesterReputation {
1557
1559
  total_points: number;
1558
1560
  }
1559
1561
 
1562
+ /** Header carrying the signed end-user identity token (verified server-side). */
1563
+ declare const MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
1564
+ /** Project scope header — paired with the API key on every SDK request. */
1565
+ declare const MUSHI_PROJECT_HEADER = "X-Mushi-Project";
1566
+ /** Build-time SDK package identity — recorded on every authenticated heartbeat. */
1567
+ declare const MUSHI_SDK_PACKAGE_HEADER = "X-Mushi-SDK-Package";
1568
+ declare const MUSHI_SDK_VERSION_HEADER = "X-Mushi-SDK-Version";
1569
+ /** Build the standard authenticated SDK ingest headers (shared by api-client + offline flush). */
1570
+ declare function buildSdkIngestHeaders(opts: {
1571
+ apiKey: string;
1572
+ projectId: string;
1573
+ sdkPackage?: string;
1574
+ sdkVersion?: string;
1575
+ userToken?: string | null;
1576
+ internalKind?: MushiInternalRequestKind;
1577
+ }): Record<string, string>;
1560
1578
  interface ApiClientOptions {
1561
1579
  projectId: string;
1562
1580
  apiKey: string;
@@ -2148,4 +2166,50 @@ declare function buildIdentityClaims(input: {
2148
2166
  */
2149
2167
  declare function parseIdentityToken(token: string): MushiIdentityClaims | null;
2150
2168
 
2151
- export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_MOTION, MUSHI_RADIUS, MUSHI_SPACING, MUSHI_TYPE, 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, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, buildIdentityClaims, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, parseIdentityToken, resolveEnvConfig, resolveRegionEndpoint, scrubPii };
2169
+ /**
2170
+ * Shared favicon resolution helpers for admin console and SDK widget.
2171
+ */
2172
+ interface ProjectFaviconSource {
2173
+ project_id: string;
2174
+ project_name: string;
2175
+ project_slug: string;
2176
+ /** Operator override — wins over inferred domain when set. */
2177
+ icon_url?: string | null;
2178
+ /** e.g. https://kensaur.us — from SDK heartbeat or API key last_seen_origin */
2179
+ sdk_origin?: string | null;
2180
+ /** Connected GitHub/GitLab repo — used when SDK has not heartbeated yet. */
2181
+ repo_url?: string | null;
2182
+ }
2183
+ declare function isUntrustedFaviconUrl(url: string): boolean;
2184
+ /** Per-domain favicon URLs — first-party assets only (no CDN globes). */
2185
+ declare function faviconUrlCandidates(domain: string, _size?: number): string[];
2186
+ /** Ordered unique domains to try for a project (most specific first). */
2187
+ declare function resolveProjectFaviconDomains(source: ProjectFaviconSource): string[];
2188
+ /** Flat URL list across all candidate domains for a project. */
2189
+ declare function projectFaviconUrlCandidates(source: ProjectFaviconSource, size?: number): string[];
2190
+ declare function originToDomain(origin: string): string | null;
2191
+ /** Derive a production hostname from a connected repo URL when possible. */
2192
+ declare function githubRepoDomainHint(repoUrl: string | null | undefined): string | null;
2193
+ /** Best single domain — first entry from {@link resolveProjectFaviconDomains}. */
2194
+ declare function resolveProjectDomain(source: ProjectFaviconSource): string | null;
2195
+ /**
2196
+ * Google's favicon CDN returns HTTP 200 with a gray globe when it has no icon.
2197
+ * Treat low-saturation loaded images as "miss" so callers try the next URL or initials.
2198
+ */
2199
+ declare function isLikelyGenericFavicon(img: HTMLImageElement): boolean;
2200
+ /** Two-letter initials for favicon fallback chips. */
2201
+ declare function projectInitials(name: string): string;
2202
+ /** Stable theme index (0–4) for initials chip coloring. */
2203
+ declare function projectInitialsThemeIndex(projectId: string): number;
2204
+ /**
2205
+ * Read the host page favicon href (web SDK only).
2206
+ *
2207
+ * Security: the host page declares this value, so it could be a `data:`,
2208
+ * `blob:`, or `javascript:` URL. Since the result is rendered into an
2209
+ * `<img src>` inside the widget, only same-trust http(s) (and protocol-relative)
2210
+ * URLs are returned; anything else falls back to `null` so the widget renders
2211
+ * its default mark instead of an unvalidated, host-controlled resource.
2212
+ */
2213
+ declare function readPageFaviconHref(): string | null;
2214
+
2215
+ export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_MOTION, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, 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, estimateJsonBytes, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, scrubPii };
package/dist/index.d.ts CHANGED
@@ -1536,6 +1536,8 @@ interface MushiCrossAppReport {
1536
1536
  project_id: string | null;
1537
1537
  app_name: string | null;
1538
1538
  app_slug: string | null;
1539
+ /** Hostname from latest SDK heartbeat — used for favicon in cross-app list. */
1540
+ app_domain?: string | null;
1539
1541
  }
1540
1542
  /** A single entry in the global tester leaderboard. */
1541
1543
  interface MushiLeaderboardEntry {
@@ -1557,6 +1559,22 @@ interface MushiTesterReputation {
1557
1559
  total_points: number;
1558
1560
  }
1559
1561
 
1562
+ /** Header carrying the signed end-user identity token (verified server-side). */
1563
+ declare const MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
1564
+ /** Project scope header — paired with the API key on every SDK request. */
1565
+ declare const MUSHI_PROJECT_HEADER = "X-Mushi-Project";
1566
+ /** Build-time SDK package identity — recorded on every authenticated heartbeat. */
1567
+ declare const MUSHI_SDK_PACKAGE_HEADER = "X-Mushi-SDK-Package";
1568
+ declare const MUSHI_SDK_VERSION_HEADER = "X-Mushi-SDK-Version";
1569
+ /** Build the standard authenticated SDK ingest headers (shared by api-client + offline flush). */
1570
+ declare function buildSdkIngestHeaders(opts: {
1571
+ apiKey: string;
1572
+ projectId: string;
1573
+ sdkPackage?: string;
1574
+ sdkVersion?: string;
1575
+ userToken?: string | null;
1576
+ internalKind?: MushiInternalRequestKind;
1577
+ }): Record<string, string>;
1560
1578
  interface ApiClientOptions {
1561
1579
  projectId: string;
1562
1580
  apiKey: string;
@@ -2148,4 +2166,50 @@ declare function buildIdentityClaims(input: {
2148
2166
  */
2149
2167
  declare function parseIdentityToken(token: string): MushiIdentityClaims | null;
2150
2168
 
2151
- export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_MOTION, MUSHI_RADIUS, MUSHI_SPACING, MUSHI_TYPE, 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, REGION_ENDPOINTS, type RateLimiter, type RateLimiterConfig, type ResolvedEnvConfig, buildIdentityClaims, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, parseIdentityToken, resolveEnvConfig, resolveRegionEndpoint, scrubPii };
2169
+ /**
2170
+ * Shared favicon resolution helpers for admin console and SDK widget.
2171
+ */
2172
+ interface ProjectFaviconSource {
2173
+ project_id: string;
2174
+ project_name: string;
2175
+ project_slug: string;
2176
+ /** Operator override — wins over inferred domain when set. */
2177
+ icon_url?: string | null;
2178
+ /** e.g. https://kensaur.us — from SDK heartbeat or API key last_seen_origin */
2179
+ sdk_origin?: string | null;
2180
+ /** Connected GitHub/GitLab repo — used when SDK has not heartbeated yet. */
2181
+ repo_url?: string | null;
2182
+ }
2183
+ declare function isUntrustedFaviconUrl(url: string): boolean;
2184
+ /** Per-domain favicon URLs — first-party assets only (no CDN globes). */
2185
+ declare function faviconUrlCandidates(domain: string, _size?: number): string[];
2186
+ /** Ordered unique domains to try for a project (most specific first). */
2187
+ declare function resolveProjectFaviconDomains(source: ProjectFaviconSource): string[];
2188
+ /** Flat URL list across all candidate domains for a project. */
2189
+ declare function projectFaviconUrlCandidates(source: ProjectFaviconSource, size?: number): string[];
2190
+ declare function originToDomain(origin: string): string | null;
2191
+ /** Derive a production hostname from a connected repo URL when possible. */
2192
+ declare function githubRepoDomainHint(repoUrl: string | null | undefined): string | null;
2193
+ /** Best single domain — first entry from {@link resolveProjectFaviconDomains}. */
2194
+ declare function resolveProjectDomain(source: ProjectFaviconSource): string | null;
2195
+ /**
2196
+ * Google's favicon CDN returns HTTP 200 with a gray globe when it has no icon.
2197
+ * Treat low-saturation loaded images as "miss" so callers try the next URL or initials.
2198
+ */
2199
+ declare function isLikelyGenericFavicon(img: HTMLImageElement): boolean;
2200
+ /** Two-letter initials for favicon fallback chips. */
2201
+ declare function projectInitials(name: string): string;
2202
+ /** Stable theme index (0–4) for initials chip coloring. */
2203
+ declare function projectInitialsThemeIndex(projectId: string): number;
2204
+ /**
2205
+ * Read the host page favicon href (web SDK only).
2206
+ *
2207
+ * Security: the host page declares this value, so it could be a `data:`,
2208
+ * `blob:`, or `javascript:` URL. Since the result is rendered into an
2209
+ * `<img src>` inside the widget, only same-trust http(s) (and protocol-relative)
2210
+ * URLs are returned; anything else falls back to `null` so the widget renders
2211
+ * its default mark instead of an unvalidated, host-controlled resource.
2212
+ */
2213
+ declare function readPageFaviconHref(): string | null;
2214
+
2215
+ export { type ApiClientOptions, type BreadcrumbBuffer, type BreadcrumbBufferOptions, DEFAULT_API_ENDPOINT, type LogEntry, type LogFormat, type LogLevel, type Logger, type LoggerOptions, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_MOTION, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, 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, estimateJsonBytes, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, scrubPii };
package/dist/index.js CHANGED
@@ -41,9 +41,23 @@ function formatBytes(n) {
41
41
  }
42
42
 
43
43
  // src/api-client.ts
44
+ var _credWarningEmitted = false;
44
45
  var MUSHI_USER_TOKEN_HEADER = "X-Mushi-User-Token";
46
+ var MUSHI_PROJECT_HEADER = "X-Mushi-Project";
45
47
  var MUSHI_SDK_PACKAGE_HEADER = "X-Mushi-SDK-Package";
46
48
  var MUSHI_SDK_VERSION_HEADER = "X-Mushi-SDK-Version";
49
+ function buildSdkIngestHeaders(opts) {
50
+ const headers = {
51
+ "Content-Type": "application/json",
52
+ "X-Mushi-Api-Key": opts.apiKey,
53
+ [MUSHI_PROJECT_HEADER]: opts.projectId
54
+ };
55
+ if (opts.sdkPackage) headers[MUSHI_SDK_PACKAGE_HEADER] = opts.sdkPackage;
56
+ if (opts.sdkVersion) headers[MUSHI_SDK_VERSION_HEADER] = opts.sdkVersion;
57
+ if (opts.userToken) headers[MUSHI_USER_TOKEN_HEADER] = opts.userToken;
58
+ if (opts.internalKind) headers[MUSHI_INTERNAL_HEADER] = opts.internalKind;
59
+ return headers;
60
+ }
47
61
  var DEFAULT_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api";
48
62
  var MUSHI_INTERNAL_HEADER = "X-Mushi-Internal";
49
63
  var MUSHI_INTERNAL_INIT_MARKER = "__mushiInternal";
@@ -70,13 +84,14 @@ function createApiClient(options) {
70
84
  const response = await fetch(url, {
71
85
  method,
72
86
  headers: {
73
- "Content-Type": "application/json",
74
- "X-Mushi-Api-Key": apiKey,
75
- "X-Mushi-Project": projectId,
76
- ...sdkPackage ? { [MUSHI_SDK_PACKAGE_HEADER]: sdkPackage } : {},
77
- ...sdkVersion ? { [MUSHI_SDK_VERSION_HEADER]: sdkVersion } : {},
78
- ...userToken ? { [MUSHI_USER_TOKEN_HEADER]: userToken } : {},
79
- ...internalKind ? { [MUSHI_INTERNAL_HEADER]: internalKind } : {},
87
+ ...buildSdkIngestHeaders({
88
+ apiKey,
89
+ projectId,
90
+ sdkPackage,
91
+ sdkVersion,
92
+ userToken,
93
+ internalKind
94
+ }),
80
95
  ...extraHeaders
81
96
  },
82
97
  body: body ? JSON.stringify(body) : void 0,
@@ -96,6 +111,13 @@ function createApiClient(options) {
96
111
  }
97
112
  if (!response.ok) {
98
113
  const errorBody = await response.json().catch(() => ({}));
114
+ if ((response.status === 401 || response.status === 403) && !_credWarningEmitted) {
115
+ _credWarningEmitted = true;
116
+ const where = baseUrl === DEFAULT_API_ENDPOINT ? "Get the correct values at: https://kensaur.us/mushi-mushi/admin/projects" : "Get the correct values from your Mushi console's Projects page.";
117
+ console.error(
118
+ `[Mushi] Credentials rejected (HTTP ${response.status}). Check your Project ID and API key scope (must be "report:write"). ` + where
119
+ );
120
+ }
99
121
  if (response.status >= 500 && retries > 0) {
100
122
  await sleep(getBackoffDelay(maxRetries - retries));
101
123
  return request(method, path, body, retries - 1, internalKind, extraHeaders);
@@ -1804,6 +1826,190 @@ function parseIdentityToken(token) {
1804
1826
  }
1805
1827
  }
1806
1828
 
1807
- export { DEFAULT_API_ENDPOINT, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_MOTION, MUSHI_RADIUS, MUSHI_SPACING, MUSHI_TYPE, MUSHI_Z, REGION_ENDPOINTS, buildIdentityClaims, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, parseIdentityToken, resolveEnvConfig, resolveRegionEndpoint, scrubPii };
1829
+ // src/favicon.ts
1830
+ var MULTI_TENANT_PARENT_HOSTS = /* @__PURE__ */ new Set(["kensaur.us", "www.kensaur.us"]);
1831
+ var SLUG_DOMAIN_HINTS = {
1832
+ "glot-it": "glot.it",
1833
+ glotit: "glot.it",
1834
+ "solo-boss-cloud": "sbc-front.vercel.app",
1835
+ "mushi-mushi": "mushimushi.dev"
1836
+ };
1837
+ var SLUG_ICON_URL_HINTS = {
1838
+ "mushi-mushi": "https://kensaur.us/mushi-mushi/admin/favicon.svg",
1839
+ "solo-boss-cloud": "https://sbc-front.vercel.app/favicon.svg",
1840
+ "glot-it": "https://kensaur.us/glot-it/apple-touch-icon.png",
1841
+ glotit: "https://kensaur.us/glot-it/apple-touch-icon.png"
1842
+ };
1843
+ var UNTRUSTED_FAVICON_HOSTS = [
1844
+ "www.google.com",
1845
+ "icons.duckduckgo.com",
1846
+ "icon.horse"
1847
+ ];
1848
+ function isUntrustedFaviconUrl(url) {
1849
+ try {
1850
+ const host = new URL(url).hostname.toLowerCase();
1851
+ return UNTRUSTED_FAVICON_HOSTS.some((h) => host === h || host.endsWith(`.${h}`));
1852
+ } catch {
1853
+ return false;
1854
+ }
1855
+ }
1856
+ function faviconUrlCandidates(domain, _size = 32) {
1857
+ return [
1858
+ `https://${domain}/favicon.svg`,
1859
+ `https://${domain}/favicon.ico`,
1860
+ `https://${domain}/favicon-32x32.png`,
1861
+ `https://${domain}/apple-touch-icon.png`
1862
+ ];
1863
+ }
1864
+ function resolveProjectFaviconDomains(source) {
1865
+ const out = [];
1866
+ const add = (d) => {
1867
+ const n = d?.trim().toLowerCase();
1868
+ if (!n || out.includes(n)) return;
1869
+ out.push(n);
1870
+ };
1871
+ add(githubRepoDomainHint(source.repo_url));
1872
+ add(SLUG_DOMAIN_HINTS[source.project_slug.toLowerCase()]);
1873
+ const fromOrigin = source.sdk_origin ? originToDomain(source.sdk_origin) : null;
1874
+ if (fromOrigin && !MULTI_TENANT_PARENT_HOSTS.has(fromOrigin)) {
1875
+ add(fromOrigin);
1876
+ }
1877
+ return out;
1878
+ }
1879
+ function projectFaviconUrlCandidates(source, size = 32) {
1880
+ if (source.icon_url?.trim()) return [source.icon_url.trim()];
1881
+ const seen = /* @__PURE__ */ new Set();
1882
+ const urls = [];
1883
+ const push = (url) => {
1884
+ if (!url || seen.has(url) || isUntrustedFaviconUrl(url)) return;
1885
+ seen.add(url);
1886
+ urls.push(url);
1887
+ };
1888
+ const slugHint = SLUG_ICON_URL_HINTS[source.project_slug.toLowerCase()];
1889
+ if (slugHint) push(slugHint);
1890
+ for (const domain of resolveProjectFaviconDomains(source)) {
1891
+ for (const url of faviconUrlCandidates(domain, size)) {
1892
+ push(url);
1893
+ }
1894
+ }
1895
+ return urls;
1896
+ }
1897
+ function originToDomain(origin) {
1898
+ const trimmed = origin.trim();
1899
+ if (!trimmed) return null;
1900
+ if (/^(capacitor|file|content|app):/i.test(trimmed)) return null;
1901
+ try {
1902
+ const url = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
1903
+ const host = url.hostname.toLowerCase();
1904
+ if (host === "localhost" || host === "127.0.0.1" || host.endsWith(".local")) {
1905
+ return null;
1906
+ }
1907
+ return host;
1908
+ } catch {
1909
+ return null;
1910
+ }
1911
+ }
1912
+ function githubRepoDomainHint(repoUrl) {
1913
+ if (!repoUrl?.trim()) return null;
1914
+ try {
1915
+ const u = new URL(repoUrl.trim());
1916
+ const host = u.hostname.toLowerCase();
1917
+ const parts = u.pathname.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
1918
+ if (parts.length < 2) return null;
1919
+ const repo = parts[1].replace(/\.git$/i, "").toLowerCase();
1920
+ if (/^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(repo)) return repo;
1921
+ if (host === "github.com" && repo.endsWith(".github.io")) return repo;
1922
+ if (host !== "github.com" && host !== "www.github.com") return host;
1923
+ return null;
1924
+ } catch {
1925
+ return null;
1926
+ }
1927
+ }
1928
+ function resolveProjectDomain(source) {
1929
+ return resolveProjectFaviconDomains(source)[0] ?? null;
1930
+ }
1931
+ function isLikelyGenericFavicon(img) {
1932
+ if (typeof document === "undefined") return false;
1933
+ if (!img.complete || img.naturalWidth === 0 || img.naturalHeight === 0) return false;
1934
+ try {
1935
+ const canvas = document.createElement("canvas");
1936
+ const w = img.naturalWidth;
1937
+ const h = img.naturalHeight;
1938
+ canvas.width = w;
1939
+ canvas.height = h;
1940
+ const ctx = canvas.getContext("2d");
1941
+ if (!ctx) return false;
1942
+ ctx.drawImage(img, 0, 0);
1943
+ const { data } = ctx.getImageData(0, 0, w, h);
1944
+ let opaque = 0;
1945
+ let satSum = 0;
1946
+ let maxDiff = 0;
1947
+ for (let i = 0; i < data.length; i += 4) {
1948
+ const r = data[i];
1949
+ const g = data[i + 1];
1950
+ const b = data[i + 2];
1951
+ const a = data[i + 3];
1952
+ if (a < 128) continue;
1953
+ opaque++;
1954
+ const max = Math.max(r, g, b);
1955
+ const min = Math.min(r, g, b);
1956
+ const diff = max - min;
1957
+ maxDiff = Math.max(maxDiff, diff);
1958
+ satSum += diff;
1959
+ }
1960
+ if (opaque === 0) return true;
1961
+ const avgSat = satSum / opaque;
1962
+ return avgSat < 14 && maxDiff < 24;
1963
+ } catch {
1964
+ return isUntrustedFaviconUrl(img.src);
1965
+ }
1966
+ }
1967
+ function projectInitials(name) {
1968
+ const parts = name.trim().split(/[\s._-]+/).filter(Boolean);
1969
+ if (parts.length >= 2) {
1970
+ return `${parts[0][0] ?? ""}${parts[1][0] ?? ""}`.toUpperCase();
1971
+ }
1972
+ const compact = name.replace(/[^a-zA-Z0-9]/g, "");
1973
+ return (compact.slice(0, 2) || name.slice(0, 2) || "?").toUpperCase();
1974
+ }
1975
+ var INITIALS_CHIP_THEMES = [
1976
+ "info",
1977
+ "brand",
1978
+ "warn",
1979
+ "ok",
1980
+ "accent"
1981
+ ];
1982
+ function projectInitialsThemeIndex(projectId) {
1983
+ let hash = 0;
1984
+ for (let i = 0; i < projectId.length; i++) {
1985
+ hash = (hash + projectId.charCodeAt(i)) % INITIALS_CHIP_THEMES.length;
1986
+ }
1987
+ return hash;
1988
+ }
1989
+ function readPageFaviconHref() {
1990
+ if (typeof document === "undefined") return null;
1991
+ const selectors = [
1992
+ 'link[rel="icon"]',
1993
+ 'link[rel="shortcut icon"]',
1994
+ 'link[rel="apple-touch-icon"]'
1995
+ ];
1996
+ for (const sel of selectors) {
1997
+ const link = document.querySelector(sel);
1998
+ const href = link?.href;
1999
+ if (href && isSafeFaviconHref(href)) return href;
2000
+ }
2001
+ return null;
2002
+ }
2003
+ function isSafeFaviconHref(href) {
2004
+ try {
2005
+ const base = typeof location !== "undefined" ? location.href : void 0;
2006
+ const protocol = new URL(href, base).protocol;
2007
+ return protocol === "http:" || protocol === "https:";
2008
+ } catch {
2009
+ return false;
2010
+ }
2011
+ }
2012
+
2013
+ export { DEFAULT_API_ENDPOINT, MAX_REPORT_PAYLOAD_BYTES, MAX_SCREENSHOT_DATA_URL_BYTES, MUSHI_COLORS_DARK, MUSHI_COLORS_LIGHT, MUSHI_COPY, MUSHI_GEOMETRY, MUSHI_IDENTITY_TOKEN_PREFIX, MUSHI_INTERNAL_HEADER, MUSHI_INTERNAL_INIT_MARKER, MUSHI_MOTION, MUSHI_PROJECT_HEADER, MUSHI_RADIUS, MUSHI_SDK_PACKAGE_HEADER, MUSHI_SDK_VERSION_HEADER, MUSHI_SPACING, MUSHI_TYPE, MUSHI_USER_TOKEN_HEADER, MUSHI_Z, REGION_ENDPOINTS, buildIdentityClaims, buildSdkIngestHeaders, captureEnvironment, checkReportPayloadSize, createApiClient, createBreadcrumbBuffer, createLogger, createOfflineQueue, createPiiScrubber, createPreFilter, createRateLimiter, estimateJsonBytes, faviconUrlCandidates, formatBytes, getDeviceFingerprintHash, getReporterToken, getSessionId, githubRepoDomainHint, isLikelyGenericFavicon, isUntrustedFaviconUrl, mushiPalette, mushiTokens, newUuid, noopLogger, normaliseThrown, originToDomain, parseIdentityToken, projectFaviconUrlCandidates, projectInitials, projectInitialsThemeIndex, readPageFaviconHref, resolveEnvConfig, resolveProjectDomain, resolveProjectFaviconDomains, resolveRegionEndpoint, scrubPii };
1808
2014
  //# sourceMappingURL=index.js.map
1809
2015
  //# sourceMappingURL=index.js.map