@sanity/sdk 3.9.1 → 3.9.2-next.20261014121948

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.
Files changed (27) hide show
  1. package/dist/_exports/_internal.d.ts +2 -2
  2. package/dist/_exports/_internal.js +9 -17
  3. package/dist/_exports/_internal.js.map +1 -1
  4. package/dist/_exports/agent.js +1 -1
  5. package/dist/_exports/comlink.d.ts +1 -0
  6. package/dist/_exports/comlink.d.ts.map +1 -1
  7. package/dist/_exports/comlink.js +1 -1
  8. package/dist/_exports/dashboard.d.ts +2 -2
  9. package/dist/_exports/dashboard.js +2 -2
  10. package/dist/{applications-DowvM7CN.d.ts → applications-CkDu_W5X.d.ts} +3 -3
  11. package/dist/{applications-DowvM7CN.d.ts.map → applications-CkDu_W5X.d.ts.map} +1 -1
  12. package/dist/{authStore-KH1GNOOB.js → authStore-DwKgZOzo.js} +8 -26
  13. package/dist/{authStore-KH1GNOOB.js.map → authStore-DwKgZOzo.js.map} +1 -1
  14. package/dist/{bus-ClLO0kQU.d.ts → bus-bvKfVggT.d.ts} +2 -2
  15. package/dist/{bus-ClLO0kQU.d.ts.map → bus-bvKfVggT.d.ts.map} +1 -1
  16. package/dist/{clientStore-DW3iIcbg.js → clientStore-DnMH7LPG.js} +2 -2
  17. package/dist/{clientStore-DW3iIcbg.js.map → clientStore-DnMH7LPG.js.map} +1 -1
  18. package/dist/{getNodeState-CkxvEZD5.js → getNodeState-Bp9sxNE1.js} +2 -5
  19. package/dist/{getNodeState-CkxvEZD5.js.map → getNodeState-Bp9sxNE1.js.map} +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +50 -74
  22. package/dist/index.js.map +1 -1
  23. package/dist/{topicStore-CU-oF3fc.js → topicStore-CNzfuPGY.js} +2 -2
  24. package/dist/{topicStore-CU-oF3fc.js.map → topicStore-CNzfuPGY.js.map} +1 -1
  25. package/dist/{version-7EzMhxQE.js → version-Bx_0tNcN.js} +10 -14
  26. package/dist/{version-7EzMhxQE.js.map → version-Bx_0tNcN.js.map} +1 -1
  27. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"authStore-KH1GNOOB.js","names":["createClient","\"DEBUG\"","\"NODE_ENV\"","\"internal\"","\"LOGGED_IN\"","\"LOGGING_IN\"","\"ERROR\"","\"LOGGED_OUT\""],"sources":["../src/utils/logger.ts","../src/utils/getStagingApiHost.ts","../src/auth/authLogger.ts","../src/dashboard/messageBus/topics.ts","../src/dashboard/messageBus/bus.ts","../src/auth/authConstants.ts","../src/auth/authMode.ts","../src/auth/authStateType.ts","../src/auth/refreshStampedToken.ts","../src/auth/subscribeToStateAndFetchCurrentUser.ts","../src/auth/utils.ts","../src/auth/dashboardAuth.ts","../src/auth/oauth/oauthClient.ts","../src/auth/oauth/oauthRefresh.ts","../src/auth/oauth/oauthAuth.ts","../src/auth/subscribeToStorageEventsAndSetToken.ts","../src/auth/standaloneAuth.ts","../src/auth/studioModeAuth.ts","../src/auth/studioAuth.ts","../src/auth/authStore.ts"],"sourcesContent":["/**\n * Logging infrastructure for the Sanity SDK\n *\n * Provides multi-level, namespace-based logging for both SDK users and maintainers.\n * In production builds, all logging can be stripped via tree-shaking.\n *\n * @example SDK User\n * ```ts\n * import {configureLogging} from '@sanity/sdk'\n *\n * configureLogging({\n * level: 'info',\n * namespaces: ['auth', 'document']\n * })\n * ```\n *\n * @example SDK Maintainer\n * ```ts\n * configureLogging({\n * level: 'trace',\n * namespaces: ['*'],\n * internal: true\n * })\n * ```\n */\n\n/**\n * Log levels in order of verbosity (least to most)\n * - error: Critical failures that prevent operation\n * - warn: Issues that may cause problems but don't stop execution\n * - info: High-level informational messages (SDK user level)\n * - debug: Detailed debugging information (maintainer level)\n * - trace: Very detailed tracing (maintainer level, includes RxJS streams)\n * @public\n */\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace'\n\n/**\n * Log namespaces organize logs by functional domain\n *\n * @remarks\n * This is an extensible string type. As logging is added to more modules,\n * additional namespaces will be recognized. Currently implemented namespaces\n * will be documented as they are added.\n * @internal\n */\nexport type LogNamespace = string\n\n/**\n * Configuration for the logging system\n * @public\n */\nexport interface LoggerConfig {\n /**\n * Minimum log level to output\n * @defaultValue 'warn'\n */\n level?: LogLevel\n\n /**\n * Namespaces to enable. Use ['*'] for all namespaces\n * @defaultValue []\n * @remarks\n * Available namespaces depend on which modules have logging integrated.\n * Check the SDK documentation for the current list of instrumented modules.\n * @example ['auth', 'document']\n */\n namespaces?: string[]\n\n /**\n * Enable internal/maintainer-level logging\n * Shows RxJS streams, store internals, etc.\n * @defaultValue false\n */\n internal?: boolean\n\n /**\n * Custom log handler (for testing or custom output)\n * @defaultValue console methods\n */\n handler?: LogHandler\n\n /**\n * Enable timestamps in log output\n * @defaultValue true\n */\n timestamps?: boolean\n\n /**\n * Enable in production builds\n * @defaultValue false\n */\n enableInProduction?: boolean\n}\n\n/**\n * Custom log handler interface\n *\n * @internal\n */\nexport interface LogHandler {\n error: (message: string, context?: LogContext) => void\n warn: (message: string, context?: LogContext) => void\n info: (message: string, context?: LogContext) => void\n debug: (message: string, context?: LogContext) => void\n trace: (message: string, context?: LogContext) => void\n}\n\n/**\n * Context object attached to log messages\n *\n * This interface allows you to attach arbitrary contextual data to log messages.\n * The index signature `[key: string]: unknown` enables you to add any custom\n * properties relevant to your log entry (e.g., `userId`, `documentId`, `action`, etc.).\n *\n * **Sensitive data sanitization:**\n * Top-level keys containing sensitive names (`token`, `password`, `secret`, `apiKey`,\n * `authorization`) are automatically redacted to `[REDACTED]` in log output.\n *\n * @example\n * ```ts\n * logger.info('User logged in', {\n * userId: '123', // Custom context\n * action: 'login', // Custom context\n * token: 'secret' // Will be redacted to [REDACTED]\n * })\n * ```\n *\n * @internal\n */\nexport interface LogContext {\n /**\n * Custom context properties that provide additional information about the log entry.\n * Any key-value pairs can be added here (e.g., userId, documentId, requestId, etc.).\n * Keys with sensitive names (token, password, secret, apiKey, authorization) are\n * automatically sanitized.\n */\n [key: string]: unknown\n /** Error object if logging an error */\n error?: Error | unknown\n /** Duration in milliseconds for timed operations */\n duration?: number\n /** Stack trace for debugging */\n stack?: string\n /** Instance context (automatically added when available) */\n instanceContext?: InstanceContext\n}\n\n/**\n * Instance context information automatically added to logs\n * @internal\n */\nexport interface InstanceContext {\n /** Unique instance ID */\n instanceId?: string\n /** Project ID */\n projectId?: string\n /** Dataset name */\n dataset?: string\n}\n\n/**\n * Logger instance for a specific namespace\n * @internal\n */\nexport interface Logger {\n readonly namespace: string\n error: (message: string, context?: LogContext) => void\n warn: (message: string, context?: LogContext) => void\n info: (message: string, context?: LogContext) => void\n debug: (message: string, context?: LogContext) => void\n trace: (message: string, context?: LogContext) => void\n /** Check if a log level is enabled (for performance-sensitive code) */\n isLevelEnabled: (level: LogLevel) => boolean\n /** Create a child logger with extended context */\n child: (context: LogContext) => Logger\n /** Get the instance context if available */\n getInstanceContext: () => InstanceContext | undefined\n}\n\n// Log level priority (lower number = higher priority)\nconst LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n}\n\n// Default logging configuration\nconst DEFAULT_CONFIG: Required<LoggerConfig> = {\n level: 'warn',\n namespaces: [],\n internal: false,\n timestamps: true,\n enableInProduction: false,\n handler: {\n // eslint-disable-next-line no-console\n error: console.error.bind(console),\n // eslint-disable-next-line no-console\n warn: console.warn.bind(console),\n // eslint-disable-next-line no-console\n info: console.info.bind(console),\n // eslint-disable-next-line no-console\n debug: console.debug.bind(console),\n // eslint-disable-next-line no-console\n trace: console.debug.bind(console), // trace uses console.debug\n },\n}\n\n/**\n * Parse DEBUG environment variable for automatic logging configuration\n *\n * Supports patterns similar to Sanity CLI/Studio:\n * - DEBUG=sanity:* (all namespaces, debug level)\n * - DEBUG=sanity:auth,sanity:document (specific namespaces)\n * - DEBUG=sanity:trace:* (all namespaces, trace level)\n * - DEBUG=sanity:*:internal (enable internal logs)\n *\n * @internal\n */\nexport function parseDebugEnvVar(): Partial<LoggerConfig> | null {\n if (typeof process === 'undefined' || !process.env?.['DEBUG']) {\n return null\n }\n\n const debug = process.env['DEBUG']\n\n // Only process if it includes 'sanity'\n if (!debug.includes('sanity')) {\n return null\n }\n\n const config: Partial<LoggerConfig> = {}\n\n // Parse level from pattern like \"sanity:trace:*\" or \"sanity:debug:*\"\n const levelMatch = debug.match(/sanity:(trace|debug|info|warn|error):/)\n const hasLevelSpecifier = !!levelMatch\n if (levelMatch) {\n config.level = levelMatch[1] as LogLevel\n } else {\n // Default to debug level if just \"sanity:*\" or \"sanity:namespace\"\n config.level = 'debug'\n }\n\n // Parse namespaces\n if (debug === 'sanity') {\n config.namespaces = ['*']\n } else if (hasLevelSpecifier && debug.match(/sanity:(trace|debug|info|warn|error):\\*/)) {\n // Pattern like \"sanity:trace:*\" - wildcard after level\n config.namespaces = ['*']\n } else if (!hasLevelSpecifier && debug.includes('sanity:*')) {\n // Pattern like \"sanity:*\" - wildcard without level\n config.namespaces = ['*']\n } else {\n // Extract specific namespaces like \"sanity:auth,sanity:document\"\n const namespaces = debug\n .split(',')\n .filter((s) => s.includes('sanity:'))\n .map((s) => {\n // Remove 'sanity:' prefix\n const cleaned = s.replace(/^sanity:/, '')\n // If there's a level specifier, skip it\n if (hasLevelSpecifier && cleaned.match(/^(trace|debug|info|warn|error):/)) {\n // Get the part after the level: \"trace:auth\" -> \"auth\"\n return cleaned.split(':').slice(1).join(':')\n }\n // Otherwise get the first part: \"auth:something\" -> \"auth\"\n return cleaned.split(':')[0]\n })\n .filter(Boolean)\n .filter((ns) => ns !== '*') // Filter out wildcards\n\n if (namespaces.length > 0) {\n config.namespaces = namespaces\n }\n }\n\n // Check for internal flag: DEBUG=sanity:*:internal\n if (debug.includes(':internal')) {\n config.internal = true\n }\n\n return config\n}\n\n// Global configuration - initialized with env var settings if present\nconst envConfig = parseDebugEnvVar()\nlet globalConfig: Required<LoggerConfig> = {\n ...DEFAULT_CONFIG,\n ...(envConfig ?? {}),\n}\n\n// Log that env var configuration was detected (only if DEBUG is set)\n// Note: This runs at module initialization, difficult to test without complex module mocking\n/* c8 ignore next 14 */\nif (envConfig) {\n const shouldLog =\n ['info', 'debug', 'trace'].includes(globalConfig.level) || globalConfig.level === 'warn'\n if (shouldLog) {\n // eslint-disable-next-line no-console\n console.info(\n `[${new Date().toISOString()}] [INFO] [sdk] Logging auto-configured from DEBUG environment variable`,\n {\n level: globalConfig.level,\n namespaces: globalConfig.namespaces,\n internal: globalConfig.internal,\n source: 'env:DEBUG',\n value: typeof process !== 'undefined' ? process.env?.['DEBUG'] : undefined,\n },\n )\n }\n}\n\n/**\n * Configure the global logging system\n * @public\n */\nexport function configureLogging(config: LoggerConfig): void {\n globalConfig = {\n ...globalConfig,\n ...config,\n handler: config.handler ?? globalConfig.handler,\n }\n}\n\n/**\n * Get the current logging configuration\n * @internal\n */\nexport function getLoggingConfig(): Readonly<Required<LoggerConfig>> {\n return globalConfig\n}\n\n/**\n * Reset logging to default configuration\n * @internal\n */\nexport function resetLogging(): void {\n globalConfig = {...DEFAULT_CONFIG}\n}\n\n/**\n * Check if logging is enabled in the current environment\n * @internal\n */\nfunction isLoggingEnabled(): boolean {\n // In production, only log if explicitly enabled\n if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] === 'production') {\n return globalConfig.enableInProduction\n }\n return true\n}\n\n/**\n * Check if a namespace is enabled\n * @internal\n */\nfunction isNamespaceEnabled(namespace: string): boolean {\n if (!isLoggingEnabled()) return false\n if (globalConfig.namespaces.includes('*')) return true\n return globalConfig.namespaces.includes(namespace)\n}\n\n/**\n * Check if a log level is enabled\n * @internal\n */\nfunction isLevelEnabled(level: LogLevel): boolean {\n if (!isLoggingEnabled()) return false\n return LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[globalConfig.level]\n}\n\n/**\n * Format a log message with timestamp, namespace, and instance context\n * @internal\n */\nfunction formatMessage(\n namespace: LogNamespace,\n level: LogLevel,\n message: string,\n context?: LogContext,\n): [string, LogContext | undefined] {\n const parts: string[] = []\n\n if (globalConfig.timestamps) {\n const timestamp = new Date().toISOString()\n parts.push(`[${timestamp}]`)\n }\n\n parts.push(`[${level.toUpperCase()}]`)\n parts.push(`[${namespace}]`)\n\n // Add instance context if available\n const instanceContext = context?.instanceContext\n if (instanceContext) {\n if (instanceContext.projectId) {\n parts.push(`[project:${instanceContext.projectId}]`)\n }\n if (instanceContext.dataset) {\n parts.push(`[dataset:${instanceContext.dataset}]`)\n }\n if (instanceContext.instanceId) {\n parts.push(`[instance:${instanceContext.instanceId.slice(0, 8)}]`)\n }\n }\n\n parts.push(message)\n\n return [parts.join(' '), context]\n}\n\n/**\n * Sanitize context for logging (remove sensitive data)\n * @internal\n * @remarks\n * This performs shallow sanitization only - it redacts top-level keys that contain\n * sensitive names (token, password, secret, apiKey, authorization).\n * Nested sensitive data (e.g., `\\{auth: \\{token: 'secret'\\}\\}`) will NOT be redacted.\n * If deep sanitization is needed in the future, this can be enhanced to recursively\n * traverse nested objects.\n */\nfunction sanitizeContext(context?: LogContext): LogContext | undefined {\n if (!context || Object.keys(context).length === 0) return undefined\n\n const sanitized = {...context}\n\n // Remove or redact sensitive fields at the top level\n const sensitiveKeys = ['token', 'password', 'secret', 'apiKey', 'authorization']\n for (const key of Object.keys(sanitized)) {\n if (sensitiveKeys.some((sensitive) => key.toLowerCase().includes(sensitive))) {\n sanitized[key] = '[REDACTED]'\n }\n }\n\n return sanitized\n}\n\n/**\n * Create a logger for a specific namespace\n * @param namespace - A string identifier for the logging domain (e.g., 'auth', 'document')\n * @param baseContext - Optional base context to include in all log messages\n * @remarks\n * If baseContext includes an `instanceContext` property (with projectId, dataset, instanceId),\n * it will be automatically formatted into the log output for easier debugging of\n * multi-instance scenarios.\n * @public\n */\nexport function createLogger(namespace: string, baseContext?: LogContext): Logger {\n const logAtLevel = (level: LogLevel, message: string, context?: LogContext) => {\n // Early return if namespace or level not enabled\n if (!isNamespaceEnabled(namespace)) return\n if (!isLevelEnabled(level)) return\n\n // Skip internal logs if not enabled\n if (context?.['internal'] && !globalConfig.internal) return\n\n const mergedContext = {...baseContext, ...context}\n const sanitized = sanitizeContext(mergedContext)\n const [formatted, finalContext] = formatMessage(namespace, level, message, sanitized)\n\n globalConfig.handler[level](formatted, finalContext)\n }\n\n const logger: Logger = {\n namespace,\n error: (message, context) => logAtLevel('error', message, context),\n warn: (message, context) => logAtLevel('warn', message, context),\n info: (message, context) => logAtLevel('info', message, context),\n debug: (message, context) => logAtLevel('debug', message, context),\n trace: (message, context) => logAtLevel('trace', message, {...context, internal: true}),\n isLevelEnabled: (level) => isNamespaceEnabled(namespace) && isLevelEnabled(level),\n child: (childContext) => createLogger(namespace, {...baseContext, ...childContext}),\n getInstanceContext: () => baseContext?.instanceContext,\n }\n\n return logger\n}\n\n/**\n * Create a performance timer for measuring operation duration\n * @internal\n */\nexport function createTimer(\n namespace: string,\n operation: string,\n): {end: (message?: string, context?: LogContext) => number} {\n const logger = createLogger(namespace)\n const start = performance.now()\n\n return {\n end: (message?: string, context?: LogContext): number => {\n const duration = performance.now() - start\n logger.debug(message ?? `${operation} completed`, {\n ...context,\n operation,\n duration,\n })\n return duration\n },\n }\n}\n\n/**\n * Utility to log RxJS operator execution (for maintainers)\n * Will be exported in future PR when logging is added to stores\n * @internal\n */\n/* c8 ignore next 4 */\nfunction logRxJSOperator(namespace: string, operator: string, context?: LogContext): void {\n const logger = createLogger(namespace)\n logger.trace(`RxJS: ${operator}`, {...context, internal: true, operator})\n}\n\n/**\n * Extract instance context from a SanityInstance for logging\n * Will be exported in future PR when logging is added to stores\n * @param instance - The SanityInstance to extract context from\n * @returns Instance context suitable for logging\n * @internal\n */\n/* c8 ignore next 7 */\nfunction getInstanceContext(instance: {\n instanceId?: string\n config?: {projectId?: string; dataset?: string}\n}): InstanceContext {\n return {\n instanceId: instance.instanceId,\n projectId: instance.config?.projectId,\n dataset: instance.config?.dataset,\n }\n}\n\n// Prevent unused function warnings - these will be exported and used in future PRs\n/* c8 ignore next 2 */\nvoid logRxJSOperator\nvoid getInstanceContext\n","declare const __SANITY_STAGING__: boolean | undefined\n\n/**\n * Returns the staging API host if the `__SANITY_STAGING__` build-time flag is\n * set to `true` (mirroring how Sanity Studio detects staging builds).\n *\n * @internal\n */\nexport function getStagingApiHost(): string | undefined {\n if (typeof __SANITY_STAGING__ !== 'undefined' && __SANITY_STAGING__ === true) {\n return 'https://api.sanity.work'\n }\n return undefined\n}\n","import {type SanityInstance} from '../store/createSanityInstance'\nimport {createLogger, type Logger} from '../utils/logger'\n\nconst loggers = new WeakMap<SanityInstance, Logger>()\n\n/**\n * Returns the auth logger for a Sanity instance, creating it on first use.\n *\n * The logger is cached per instance so repeated action calls (logout,\n * setAuthToken, handleAuthCallback) reuse the same logger instead of\n * rebuilding it. The instance details are nested under `instanceContext`,\n * which is what the logger's formatter reads to render the\n * `[project:x] [dataset:y] [instance:z]` prefix.\n *\n * @internal\n */\nexport function getAuthLogger(instance: SanityInstance): Logger {\n let logger = loggers.get(instance)\n if (!logger) {\n logger = createLogger('auth', {\n instanceContext: {\n instanceId: instance.instanceId,\n projectId: instance.config.projectId,\n dataset: instance.config.dataset,\n },\n })\n loggers.set(instance, logger)\n }\n return logger\n}\n","import {type CurrentUser} from '@sanity/types'\n\nimport {type AccessResourceType} from '../../access/checkPermissions'\nimport {type Application, type ApplicationInclude} from '../../applications/applications'\nimport {type Installation, type InstallationInclude} from '../../installations/installations'\nimport {type OrganizationBase} from '../../organization/organization'\n\n/**\n * Identifies a module federation expose and the manifest that serves it.\n * @public\n * @category Remote Modules\n */\nexport interface RemoteModuleRef {\n readonly entry: string\n readonly moduleId: string\n readonly version: string\n}\n\n/**\n * Application types that can receive configuration modules.\n *\n * The dashboard supplies this value over the message bus, so any string is accepted; known\n * types are listed for autocomplete. `& {}` keeps the literal from collapsing into `string`.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type ApplicationConfigAppType = 'media-library' | (string & {})\n\n/**\n * Identifies a configuration module for an application or application type.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport interface ApplicationConfig extends RemoteModuleRef {\n readonly appId?: Application['id']\n readonly appType: ApplicationConfigAppType\n}\n\n/**\n * The capabilities a host can provide.\n *\n * Reuses the Studio's rendering-context identifiers so an application can hide its own\n * implementation of anything the host provides.\n * @public\n * @category Message Bus\n */\nexport const capabilities = ['globalUserMenu', 'favorites', 'history'] as const\n\n/**\n * A capability a host can provide.\n * @public\n * @category Message Bus\n */\nexport type Capability = (typeof capabilities)[number]\n\n/**\n * The capabilities the host provides. A missing key means the host does not provide it.\n * @public\n * @category Message Bus\n */\nexport type CapabilityRecord = Partial<Record<Capability, boolean>>\n\n/**\n * A document a user viewed, edited, created, or deleted in an application.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport interface DocumentActivity {\n readonly kind: 'document'\n readonly eventType: 'viewed' | 'edited' | 'created' | 'deleted'\n readonly document: {\n readonly id: string\n readonly type: string\n readonly resource: {\n readonly id: string\n readonly type: 'dataset' | 'media-library' | 'canvas'\n /** Schema collection the document belongs to; the workspace name for studios. */\n readonly schemaName?: string\n }\n }\n}\n\n/**\n * Activity an application reports to the host. Discriminated on `kind`.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type ApplicationActivity = DocumentActivity\n\n/**\n * A document a user favorited, addressed like {@link DocumentActivity}'s document.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type FavoriteDocument = DocumentActivity['document']\n\n/**\n * A label rendered for an application interface; `null` clears it.\n * @internal\n */\nexport type ApplicationStatus = {label: string | null}\n\n/**\n * Updates the status rendered for an application interface.\n * @internal\n */\nexport type ApplicationStatusUpdate = {\n /** The application interface name. */\n name: string\n /** The status to render. */\n value: ApplicationStatus\n}\n\n/**\n * What an application is currently showing: the Comlink agent resource context, made generic.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport interface ApplicationContext {\n /** The resource the application is working in. Types follow `@sanity/client`'s resource config. */\n readonly resource: {\n readonly id: string\n readonly type: 'dataset' | 'media-library' | 'canvas'\n }\n /** The open document, or `null` when none is open. */\n readonly document: {readonly id: string} | null\n}\n\n/**\n * An application served by a CLI dev server. The workbench publishes it in the same shape as a\n * deployed application; `local` marks it and names the dev server it is served from.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type LocalApplication = Application<ApplicationInclude> & {\n readonly local: {readonly host: string; readonly port: number}\n}\n\n/**\n * Declares a topic that stores and replays its current value.\n * @public\n * @category Message Bus\n */\nexport type StateTopicDef<T> = {kind: 'state'; value: T}\n\n/**\n * Declares a topic that delivers events and an optional reply.\n * @public\n * @category Message Bus\n */\nexport type EventTopicDef<P, R = never> = {\n kind: 'event'\n payload: P\n reply?: R\n}\n\n/**\n * Represents a successful topic value or a failed topic operation.\n * @public\n * @category Message Bus\n */\nexport type TopicResult<T> = {ok: true; value: T} | {ok: false}\n\n/**\n * Identifies a dashboard application and a route within it.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type NavigationTarget = {\n /** The application ID, or `null` for dashboard-level routes. */\n appId: Application['id'] | null\n /** The route path, including its query string and fragment. */\n path: string\n}\n\n/**\n * Describes the current dashboard location and an active navigation.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type NavigationLocation = NavigationTarget & {\n /** The active navigation, or `null` when navigation is idle. */\n transition: {\n /** Whether the navigation pushes or replaces browser history. */\n navigationType: 'push' | 'replace'\n /** The requested destination. */\n to: NavigationTarget\n } | null\n}\n\n/**\n * Declares the topics provided by the dashboard.\n * @public\n * @category Message Bus\n */\nexport interface DashboardTopics {\n /**\n * Asks the dashboard to show its access request prompt for a resource the user can't access,\n * scoped like the Access API's `/access/{resourceType}/{resourceId}/requests`. Replies once the\n * prompt is shown. The prompt handles the Access API outcome (SSO enforcement, pending or\n * declined requests, request limits), so the reply doesn't report it.\n *\n * `ok: false` reasons:\n * - `unsupported`: the dashboard doesn't show access requests for the sending application\n * - `already-has-access`: the user already has access to the resource, so there is nothing to request\n */\n 'access.request': EventTopicDef<\n {resourceType: Extract<AccessResourceType, 'organization' | 'project'>; resourceId: string},\n {ok: true} | {ok: false; reason: 'unsupported' | 'already-has-access'}\n >\n /** Reports user activity in an application, e.g. for the recents feed. Fire-and-forget. */\n 'applications.activity': EventTopicDef<ApplicationActivity>\n /**\n * The base path for an application.\n *\n * An unknown application returns `{ok: false}`.\n */\n 'applications.base-path': StateTopicDef<TopicResult<string>>\n /** The capabilities the host provides. A missing key means the host does not provide it. */\n 'applications.capabilities': StateTopicDef<CapabilityRecord>\n /** The available application configuration modules. */\n 'applications.config': StateTopicDef<ApplicationConfig[] | null>\n /** The foreground application's context, or `null` when it has published none. */\n 'applications.context': StateTopicDef<\n (ApplicationContext & {readonly appId: Application['id']}) | null\n >\n /** Publishes the sending application's context. `null` clears it. Fire-and-forget. */\n 'applications.context.update': EventTopicDef<ApplicationContext | null>\n /** The foreground application ID, or `null` on dashboard-level routes. */\n 'applications.foreground': StateTopicDef<Application['id'] | null>\n /**\n * The dashboard applications and installations available to the current user. Each member\n * publishes its own raw serialised record, so the kinds are distinguished by shape: an\n * {@link Application} has a `type` of `'studio' | 'coreApp'`, a {@link LocalApplication} adds\n * `local`, and an {@link Installation} has no `type` and carries `applicationId` with a nested\n * `application` object.\n */\n 'applications.list': StateTopicDef<TopicResult<\n (Application<ApplicationInclude> | LocalApplication | Installation<InstallationInclude>)[]\n > | null>\n 'applications.status.update': EventTopicDef<ApplicationStatusUpdate>\n /**\n * The session token for the reading connection, or `null` while signed out. The host\n * writes it to each connection separately, so one application never sees another's token.\n */\n 'auth.token': StateTopicDef<string | null>\n /** Requests a dashboard session token. */\n 'auth.token.refresh': EventTopicDef<void, string>\n /** The signed-in user's favorited documents, published while the host provides `favorites`. */\n 'favorites.documents': StateTopicDef<FavoriteDocument[]>\n /**\n * Favorites or unfavorites a document. The host replies once `favorites.documents` reflects\n * the change, so a read after the reply sees it. A favorite is identified by its published\n * document ID, type, resource and `schemaName` (workspace).\n */\n 'favorites.update': EventTopicDef<{document: FavoriteDocument; favorited: boolean}, void>\n /** The current dashboard location and active navigation. */\n 'navigation.location': StateTopicDef<NavigationLocation | null>\n /**\n * Requests navigation and replies when the location commits.\n *\n * `ok: false` reasons:\n * - `not-navigable`: the URL cannot be handled by a dashboard application\n * - `interrupted`: another navigation superseded the request\n * - `failed`: the router rejected or did not commit the request\n */\n 'navigation.location.update': EventTopicDef<\n {\n url: string\n history?: 'push' | 'replace'\n },\n {ok: true} | {ok: false; reason: 'not-navigable' | 'interrupted' | 'failed'}\n >\n /** The current organization, or `null` without an active organization. */\n 'organizations.current': StateTopicDef<Pick<OrganizationBase, 'id' | 'name' | 'slug'> | null>\n /** The open panel, its application, display mode, and optional width in pixels. */\n 'panels.mode': StateTopicDef<TopicResult<\n | {appId: string; name: string; mode: 'aside'; size?: number}\n | {appId: string; name: string; mode: 'full'}\n | null\n > | null>\n /** Opens, updates, resizes, or closes an application's panel. */\n 'panels.mode.set': EventTopicDef<\n {name: string; mode: 'aside' | 'full'} | {name: string; size: number} | null\n >\n /** The resolved dashboard color scheme. */\n 'preferences.color-scheme': StateTopicDef<'light' | 'dark'>\n /** Whether the dashboard dock is pinned open. */\n 'preferences.dock-locked': StateTopicDef<boolean>\n /** The signed-in user, or `null` while signed out. */\n 'users.current': StateTopicDef<CurrentUser | null>\n}\n\n/**\n * Declares every topic available through the message bus.\n * @public\n * @category Message Bus\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- Declaration merging extends the SDK manifest.\nexport interface Topics extends DashboardTopics {}\n\n/**\n * Hides provisional topics from the public message bus methods.\n * @internal\n */\nexport type MessageBusTopics = Omit<Topics, 'applications.status.update'>\n\n/**\n * Every declared topic name.\n * @public\n * @category Message Bus\n */\nexport type TopicName<TTopics = Topics> = keyof TTopics\n\ntype StateTopicsOf<T> = {\n [K in keyof T]: T[K] extends {kind: 'state'} ? K : never\n}[keyof T]\n\n/**\n * Names of state topics exposed by message bus methods.\n * @public\n * @category Message Bus\n */\nexport type StateTopic<TTopics = MessageBusTopics> = StateTopicsOf<TTopics>\n\ntype TopicOwnership = {readonly type: 'same_app'} | {readonly type: 'any_app'}\n\n// State is only ever written by the host, one connection at a time, so it carries no ownership.\ntype TopicManifestEntry<T> = T extends {kind: 'state'; value: infer V}\n ? {readonly kind: 'state'; readonly seed: V | undefined}\n : {readonly kind: 'event'; readonly ownership: TopicOwnership}\n\n// The value a connection's copy of the topic starts with; `undefined` means unpublished.\nconst stateTopic = <const V>(seed: V) => ({kind: 'state', seed}) as const\n\n// `same_app` restricts responding to the application that installed the bus.\nconst dashboardEvent = {kind: 'event', ownership: {type: 'same_app'}} as const\n\ntype DashboardTopicManifest = {\n readonly [K in keyof DashboardTopics]: TopicManifestEntry<DashboardTopics[K]>\n}\n\n/**\n * Defines the runtime kind, ownership, and initial value of dashboard topics.\n * @internal\n */\nexport const DASHBOARD_TOPIC_MANIFEST: DashboardTopicManifest = {\n 'access.request': dashboardEvent,\n 'applications.activity': dashboardEvent,\n 'applications.base-path': stateTopic(undefined),\n 'applications.capabilities': stateTopic(undefined),\n 'applications.config': stateTopic(undefined),\n 'applications.context': stateTopic(undefined),\n 'applications.context.update': dashboardEvent,\n 'applications.foreground': stateTopic(undefined),\n 'applications.list': stateTopic(undefined),\n 'applications.status.update': dashboardEvent,\n 'auth.token': stateTopic(undefined),\n 'auth.token.refresh': dashboardEvent,\n 'favorites.documents': stateTopic(undefined),\n 'favorites.update': dashboardEvent,\n 'navigation.location': stateTopic(undefined),\n 'navigation.location.update': dashboardEvent,\n 'organizations.current': stateTopic(undefined),\n 'panels.mode': stateTopic({ok: true, value: null}),\n 'panels.mode.set': dashboardEvent,\n 'preferences.color-scheme': stateTopic(undefined),\n 'preferences.dock-locked': stateTopic(undefined),\n 'users.current': stateTopic(undefined),\n}\n\n/**\n * Defines the runtime manifest accepted from any message bus version.\n * @internal\n */\nexport type TopicManifest = Readonly<\n Record<\n string,\n | {readonly kind: 'state'; readonly seed: unknown}\n | {readonly kind: 'event'; readonly ownership: TopicOwnership}\n >\n>\n\n/**\n * Names of event topics exposed by message bus methods.\n * @public\n * @category Message Bus\n */\nexport type EventTopic<TTopics = MessageBusTopics> = {\n [K in keyof TTopics]: TTopics[K] extends {kind: 'event'} ? K : never\n}[keyof TTopics]\n\n/**\n * The value type of a state topic.\n * @public\n * @category Message Bus\n */\nexport type ValueOf<K extends StateTopic<TTopics>, TTopics = Topics> =\n TTopics[K] extends StateTopicDef<infer T> ? T : never\n\n/**\n * The payload type of an event topic.\n * @public\n * @category Message Bus\n */\nexport type PayloadOf<K extends EventTopic<TTopics>, TTopics = Topics> =\n TTopics[K] extends EventTopicDef<infer P, infer _R> ? P : never\n\n/**\n * The reply type of an event topic (`never` if it declares none).\n * @public\n * @category Message Bus\n */\nexport type ReplyOf<K extends EventTopic<TTopics>, TTopics = Topics> =\n TTopics[K] extends EventTopicDef<infer _P, infer R> ? R : never\n\n/**\n * Converts a topic value between 2 adjacent versions.\n * @internal\n */\nexport interface TopicMigration {\n /** The older version. */\n readonly from: number\n /** The newer version. */\n readonly to: number\n /** Converts an older state value or event payload to the newer version. */\n up(older: unknown): unknown\n /** Converts a newer state value or event payload to the older version. */\n down(newer: unknown): unknown\n /** Converts event replies between these versions. */\n readonly reply?: {\n /** Converts an older reply to the newer version. */\n up(older: unknown): unknown\n /** Converts a newer reply to the older version. */\n down(newer: unknown): unknown\n }\n}\n\n/**\n * Defines the bundled migration chain for each topic.\n * @internal\n */\nexport const topicMigrations: Partial<Record<TopicName, readonly TopicMigration[]>> = {}\n","/* eslint-disable no-console -- The bus can initialize before the SDK logger exists. */\nimport {\n BehaviorSubject,\n concat,\n defer,\n filter,\n firstValueFrom,\n from,\n map,\n type Observable,\n ReplaySubject,\n Subject,\n type Subscription,\n takeUntil,\n} from 'rxjs'\n\nimport {type Application} from '../../applications/applications'\nimport {\n DASHBOARD_TOPIC_MANIFEST,\n type EventTopic,\n type MessageBusTopics,\n type PayloadOf,\n type ReplyOf,\n type StateTopic,\n type TopicManifest,\n type TopicMigration,\n topicMigrations,\n type TopicName,\n type Topics,\n type ValueOf,\n} from './topics'\n\n/**\n * A message bus protocol error code.\n * @public\n * @category Message Bus\n */\nexport type MessageBusErrorCode =\n | 'NO_RESPONDER'\n | 'TIMEOUT'\n | 'ABORTED'\n | 'HANDLER_THREW'\n | 'PROTOCOL_MISMATCH'\n | 'OWNERSHIP_MISMATCH'\n | 'MISSING_APP_ID'\n | 'REFUSED'\n\n/**\n * An error raised by the message bus protocol.\n * @public\n * @category Message Bus\n */\nexport class MessageBusError extends Error {\n /** The machine-readable protocol error code. */\n readonly code: MessageBusErrorCode\n\n /** Creates a message bus protocol error. */\n constructor(code: MessageBusErrorCode, message?: string, options?: {cause?: unknown}) {\n super(message ?? code, options)\n this.name = 'MessageBusError'\n this.code = code\n }\n}\n\n/**\n * Metadata that travels with each message bus event.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusMeta {\n /** The application that produced the message. */\n appId: Application['id']\n /**\n * The federation module id of the connection that sent the message (e.g.\n * `favorites/views/list/panel`). Absent from older copies and when the host\n * supplied none, so readers normalise with `message.meta.moduleId ?? message.meta.appId`.\n */\n moduleId?: string\n /** The Unix timestamp in milliseconds when the message was produced. */\n timestamp: number\n}\n\n/**\n * A message delivered to an event topic responder.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusMessage<T, R = never, K extends PropertyKey = TopicName> {\n /** The topic that carries the message. */\n type: K\n /** The event payload. */\n payload: T\n /** The message provenance. */\n meta: MessageBusMeta\n /** Replies to an awaiting sender. */\n reply(value: R): void\n /**\n * Refuses the message: the sender's awaited `emit()` rejects with a\n * {@link MessageBusError} whose `code` is `'REFUSED'`. Ignored, with a warning,\n * once the reply has already settled.\n */\n reject(message?: string): void\n /** Aborts when the sender stops waiting for a reply. */\n readonly signal: AbortSignal\n}\n\n/**\n * An observable state topic with access to its current and first values.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusStateSource<T> extends Observable<T> {\n /** Returns the current value, or `undefined` before the first value is published. */\n getCurrent(): T | undefined\n /** Resolves with the first published value. */\n readonly firstValue: Promise<T>\n}\n\n/**\n * Options for aborting a message bus operation.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusAbortOptions {\n /** Aborts the operation when signaled. */\n signal?: AbortSignal\n}\n\n/**\n * Options for reading a state topic.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusQueryOptions extends MessageBusAbortOptions {\n /** Wait timeout in milliseconds. Defaults to 5 seconds; `null` disables it. */\n timeout?: number | null\n}\n\n/**\n * Options for emitting an event topic.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusEmitOptions extends MessageBusAbortOptions {\n /** Reply timeout in milliseconds. Defaults to 5 seconds; `null` disables it. */\n timeout?: number | null\n}\n\n/**\n * A lazily awaited event reply.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusEmitResult<R> extends PromiseLike<R> {\n /** Handles a rejected event reply. */\n catch<T = never>(onRejected?: (reason: unknown) => T | PromiseLike<T>): Promise<R | T>\n /** Runs after the event reply settles. */\n finally(onFinally?: () => void): Promise<R>\n}\n\n/**\n * Sends events and reads typed state and event topics.\n *\n * @remarks\n * State topics are written by the host to each connection separately through\n * {@link MessageBusClient.emit}; a connection only ever reads its own values.\n * @public\n * @category Message Bus\n */\nexport interface MessageBus<TTopics = MessageBusTopics> {\n /** Emits an event topic and provides its reply when awaited. */\n emit<K extends EventTopic<TTopics>>(\n type: K,\n ...rest: PayloadOf<K, TTopics> extends void\n ? [payload?: void, options?: MessageBusEmitOptions]\n : [payload: PayloadOf<K, TTopics>, options?: MessageBusEmitOptions]\n ): MessageBusEmitResult<ReplyOf<K, TTopics>>\n /** Reads the current or next value of a state topic. */\n query<K extends StateTopic<TTopics>>(\n type: K,\n options?: MessageBusQueryOptions,\n ): Promise<ValueOf<K, TTopics>>\n /** Runs a responder for each event until its signal aborts. */\n subscribe<K extends EventTopic<TTopics>>(\n type: K,\n handler: (message: MessageBusMessage<PayloadOf<K, TTopics>, ReplyOf<K, TTopics>, K>) => void,\n options?: MessageBusAbortOptions,\n ): void\n /** Runs a handler for each state value until its signal aborts. */\n subscribe<K extends StateTopic<TTopics>>(\n type: K,\n handler: (value: ValueOf<K, TTopics>) => void,\n options?: MessageBusAbortOptions,\n ): void\n /** Returns a state topic as a `MessageBusStateSource`. */\n subscribe<K extends StateTopic<TTopics>>(type: K): MessageBusStateSource<ValueOf<K, TTopics>>\n /** Returns an event topic as an observable of its payloads. */\n subscribe<K extends EventTopic<TTopics>>(type: K): Observable<PayloadOf<K, TTopics>>\n}\n\n/**\n * A message bus connection that can be torn down independently of its siblings.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusConnection<TTopics = MessageBusTopics> extends MessageBus<TTopics> {\n /** The application this connection belongs to. */\n readonly appId: Application['id']\n /**\n * Tears down this connection: pending requests reject `ABORTED`, subscriptions\n * complete, and later `emit`, `query`, and `subscribe` calls fail with `ABORTED`.\n * Siblings and the shared bus are untouched.\n */\n disconnect(): void\n}\n\n/**\n * The host's handle to one connection: who it is, when it closes, and where to write its state.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusClient {\n /** The application the connection belongs to. */\n readonly appId: Application['id']\n /** The federation module id of the connection. Equals `appId` when the host supplied none. */\n readonly moduleId: string\n /** Aborts when the connection disconnects. Drop per-client state here. */\n readonly closed: AbortSignal\n /** Writes a state value to this connection only. Ignored once the connection has closed. */\n emit<K extends StateTopic>(type: K, value: ValueOf<K>): void\n /**\n * Rejects a state topic for this connection: its pending and later {@link MessageBus.query}\n * calls reject with a {@link MessageBusError} whose `code` is `'REFUSED'`, until the host next\n * writes a value with {@link MessageBusClient.emit}, which clears the rejection.\n *\n * @remarks\n * A rejected promise cannot be un-rejected and an errored subject cannot resume, so the\n * rejection is tracked per connection alongside the topic's subject rather than by erroring\n * it: `query` consults it before awaiting, and {@link MessageBus.subscribe} and the topic's\n * {@link MessageBusStateSource} stay silent (they never error) until a value is written.\n * Ignored once the connection has closed, the same as {@link MessageBusClient.emit}.\n */\n reject<K extends StateTopic>(type: K, message?: string): void\n}\n\n/**\n * The host's connection to the bus.\n *\n * @remarks\n * State reaches an application only through {@link MessageBusClient.emit}. There is no\n * broadcast: sending the same value to everyone is a loop over `connections`, and giving a\n * new connection the current values is done when it appears there, as an SSE server writes\n * a snapshot to each new client.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusHost<TTopics = MessageBusTopics> extends MessageBusConnection<TTopics> {\n /**\n * Every open connection other than this one first, then each new one as it joins. The same\n * {@link MessageBusClient} object is handed out for a connection across subscriptions, so it\n * can be kept in a `Set`. A connection stays listed until it calls `disconnect()`; the SDK\n * does that when the owning `SanityInstance` is disposed.\n */\n readonly connections: Observable<MessageBusClient>\n}\n\nconst MESSAGE_BUS_KEY = Symbol.for('sanity.os.bus')\nconst MESSAGE_BUS_PROTOCOL_KEY = Symbol.for('sanity.os.protocol')\nconst MESSAGE_BUS_REGISTRY_KEY = Symbol.for('sanity.os.registry')\nconst MESSAGE_BUS_PENDING_REPLY_KEY = Symbol.for('sanity.os.request')\n\nconst MESSAGE_BUS_PROTOCOL = 1\n\nconst DEFAULT_TIMEOUT_MS = 5000\n\n// Distinguishes an unpublished topic from a published `undefined` value.\nconst NO_VALUE = Symbol.for('sanity.os.no-value')\n\ntype ReplyOutcome =\n | {readonly ok: true; readonly value: unknown}\n | {readonly ok: false; readonly error: unknown}\n\n// Defers Promise creation until the reply is awaited to preserve fire-and-forget emission.\ninterface PendingReply {\n readonly responderAbort: AbortController\n readonly responderSignal: AbortSignal\n settled: boolean\n outcomeBeforeAwait?: ReplyOutcome\n settlePromise?: (outcome: ReplyOutcome) => void\n replyPromise?: Promise<unknown>\n}\n\n// One connection: its identity, its own copy of every state topic, and its lifetime.\ninterface ConnectionRecord {\n readonly appId: string\n readonly moduleId: string\n readonly stateSubjects: Map<string, BehaviorSubject<unknown>>\n // Topics the host has rejected for this connection, with the reason, until the next write.\n readonly rejections: Map<string, string | undefined>\n // Fires the rejected topic name so pending queries on that topic can reject at once.\n readonly rejected$: Subject<string>\n readonly abort: AbortController\n}\n\ninterface MessageBusRegistry {\n readonly appId: string\n readonly topics: Map<string, TopicManifest[string]>\n readonly connections: Set<ConnectionRecord>\n readonly connected$: Subject<ConnectionRecord>\n readonly eventSubjects: Map<string, Subject<MessageBusMessage<unknown, unknown>>>\n readonly responderCounts: Map<string, number>\n readonly migrations: ReadonlyMap<string, readonly TopicMigration[]>\n resetAbort: AbortController\n generation: number\n}\n\ntype InternalMessageBus = MessageBus & {\n [MESSAGE_BUS_REGISTRY_KEY]: MessageBusRegistry\n [MESSAGE_BUS_PROTOCOL_KEY]: number\n}\n\n// A connection's box for a state topic, created on first use from the topic's manifest seed.\nfunction resolveStateSubject(\n registry: MessageBusRegistry,\n connection: ConnectionRecord,\n type: string,\n): BehaviorSubject<unknown> {\n // Callers gate on the connection's lifetime; this keeps a slipped call from recreating a\n // box on a closed connection that nothing would ever complete.\n if (connection.abort.signal.aborted) throw new MessageBusError('ABORTED')\n let subject = connection.stateSubjects.get(type)\n if (!subject) {\n const topic = registry.topics.get(type)\n if (!topic) {\n console.warn(`[sanity-sdk:message-bus] state topic \"${type}\" is not declared`)\n }\n const seed = topic?.kind === 'state' ? topic.seed : undefined\n subject = new BehaviorSubject<unknown>(seed === undefined ? NO_VALUE : seed)\n connection.stateSubjects.set(type, subject)\n }\n return subject\n}\n\nfunction toStateSource(\n values: Observable<unknown>,\n getCurrent: () => unknown,\n): MessageBusStateSource<unknown> {\n const source = values as MessageBusStateSource<unknown>\n source.getCurrent = getCurrent\n // Unread sources must not create promises that reject when reset completes them.\n let firstValue: Promise<unknown> | undefined\n Object.defineProperty(source, 'firstValue', {\n get: () => (firstValue ??= firstValueFrom(values)),\n })\n return source\n}\n\nfunction assertCompatibleTopicManifest(\n registry: MessageBusRegistry,\n manifest: TopicManifest,\n): void {\n for (const [type, entry] of Object.entries(manifest)) {\n const existing = registry.topics.get(type)\n if (existing && existing.kind !== entry.kind) {\n throw new MessageBusError(\n 'PROTOCOL_MISMATCH',\n `topic \"${type}\" is declared \"${entry.kind}\" but the installed bus knows it as \"${existing.kind}\"`,\n )\n }\n if (\n existing?.kind === 'event' &&\n entry.kind === 'event' &&\n existing.ownership.type !== entry.ownership.type\n ) {\n throw new MessageBusError('OWNERSHIP_MISMATCH', `topic \"${type}\" has conflicting ownership`)\n }\n }\n}\n\nfunction mergeTopicManifest(registry: MessageBusRegistry, manifest: TopicManifest): void {\n assertCompatibleTopicManifest(registry, manifest)\n for (const [type, entry] of Object.entries(manifest)) registry.topics.set(type, entry)\n}\n\nfunction resolveEventSubject(\n registry: MessageBusRegistry,\n type: string,\n): Subject<MessageBusMessage<unknown, unknown>> {\n let subject = registry.eventSubjects.get(type)\n if (!subject) {\n subject = new Subject<MessageBusMessage<unknown, unknown>>()\n registry.eventSubjects.set(type, subject)\n }\n return subject\n}\n\nfunction settleReply(reply: PendingReply, outcome: ReplyOutcome): void {\n if (reply.settled) return\n reply.settled = true\n if (reply.settlePromise) reply.settlePromise(outcome)\n else reply.outcomeBeforeAwait = outcome\n}\n\nfunction createEventMessage(\n appId: string,\n moduleId: string,\n type: string,\n payload: unknown,\n pendingReply: PendingReply,\n): MessageBusMessage<unknown, unknown> {\n const message: MessageBusMessage<unknown, unknown> & {\n [MESSAGE_BUS_PENDING_REPLY_KEY]?: PendingReply\n } = {\n type: type as TopicName,\n payload,\n meta: {appId, moduleId, timestamp: Date.now()},\n reply: (value) => {\n if (pendingReply.settled) {\n console.warn(\n `[sanity-sdk:message-bus] reply ignored for \"${type}\": no waiting caller or already replied`,\n )\n return\n }\n settleReply(pendingReply, {ok: true, value})\n },\n reject: (reason) => {\n if (pendingReply.settled) {\n console.warn(\n `[sanity-sdk:message-bus] reject ignored for \"${type}\": no waiting caller or already replied`,\n )\n return\n }\n settleReply(pendingReply, {ok: false, error: new MessageBusError('REFUSED', reason)})\n },\n get signal() {\n return pendingReply.responderSignal\n },\n }\n\n message[MESSAGE_BUS_PENDING_REPLY_KEY] = pendingReply\n return message\n}\n\nfunction createReplyPromise(\n pendingReply: PendingReply,\n options: MessageBusEmitOptions & {hadResponderAtEmission: boolean},\n): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n const settlePromise = (outcome: ReplyOutcome) =>\n outcome.ok ? resolve(outcome.value) : reject(outcome.error)\n\n if (pendingReply.outcomeBeforeAwait) {\n pendingReply.responderAbort.abort()\n settlePromise(pendingReply.outcomeBeforeAwait)\n return\n }\n if (!options.hadResponderAtEmission) {\n reject(new MessageBusError('NO_RESPONDER'))\n return\n }\n\n const timeoutMs = options.timeout === undefined ? DEFAULT_TIMEOUT_MS : options.timeout\n let timer: ReturnType<typeof setTimeout> | undefined\n const onAbort = () =>\n settleReply(pendingReply, {ok: false, error: new MessageBusError('ABORTED')})\n\n pendingReply.settlePromise = (outcome) => {\n if (timer !== undefined) clearTimeout(timer)\n options.signal?.removeEventListener('abort', onAbort)\n pendingReply.responderAbort.abort()\n settlePromise(outcome)\n }\n\n if (timeoutMs !== null) {\n timer = setTimeout(\n () => settleReply(pendingReply, {ok: false, error: new MessageBusError('TIMEOUT')}),\n timeoutMs,\n )\n }\n if (options.signal) {\n if (options.signal.aborted) onAbort()\n else options.signal.addEventListener('abort', onAbort, {once: true})\n }\n })\n}\n\nfunction createLazyReply<R>(awaitReply: () => Promise<R>): MessageBusEmitResult<R> {\n return {\n // oxlint-disable-next-line unicorn/no-thenable -- awaiting arms reply failure handling; fire-and-forget does not.\n then: (onFulfilled, onRejected) => awaitReply().then(onFulfilled, onRejected),\n catch: (onRejected) => awaitReply().then(undefined, onRejected),\n finally: (onFinally) => awaitReply().finally(onFinally),\n }\n}\n\nfunction emitEvent(\n registry: MessageBusRegistry,\n type: string,\n payload: unknown,\n options: MessageBusEmitOptions | undefined,\n appId: string,\n moduleId: string,\n): MessageBusEmitResult<unknown> {\n const hadResponderAtEmission = (registry.responderCounts.get(type) ?? 0) > 0\n const responderAbort = new AbortController()\n const pendingReply: PendingReply = {\n responderAbort,\n responderSignal: scopeSignal(options?.signal, responderAbort.signal),\n settled: false,\n }\n\n resolveEventSubject(registry, type).next(\n createEventMessage(appId, moduleId, type, payload, pendingReply),\n )\n\n const awaitReply = () =>\n (pendingReply.replyPromise ??= createReplyPromise(pendingReply, {\n ...options,\n hadResponderAtEmission,\n }))\n return createLazyReply(awaitReply)\n}\n\nconst isStateTopic = (registry: MessageBusRegistry, type: string): boolean =>\n registry.topics.get(type)?.kind === 'state'\n\nconst canRespond = (\n registry: MessageBusRegistry,\n ownership: {readonly type: 'same_app' | 'any_app'},\n appId: string,\n): boolean => ownership.type === 'any_app' || appId === registry.appId\n\nfunction emit(\n registry: MessageBusRegistry,\n type: string,\n payload: unknown,\n options: MessageBusEmitOptions | undefined,\n appId: string,\n moduleId: string,\n connectionSignal: AbortSignal,\n): MessageBusEmitResult<unknown> {\n if (isStateTopic(registry, type)) {\n throw new MessageBusError(\n 'OWNERSHIP_MISMATCH',\n `Cannot emit state topic \"${type}\" from app \"${appId}\". The host writes state to each connection through its client handle. Read it with query() or subscribe().`,\n )\n }\n return emitEvent(\n registry,\n type,\n payload,\n {\n ...options,\n signal: scopeSignal(options?.signal, registry.resetAbort.signal, connectionSignal),\n },\n appId,\n moduleId,\n )\n}\n\nfunction emitState(\n registry: MessageBusRegistry,\n connection: ConnectionRecord,\n type: string,\n value: unknown,\n): void {\n // A written value clears any rejection so later queries resolve normally.\n connection.rejections.delete(type)\n const subject = resolveStateSubject(registry, connection, type)\n if (!Object.is(subject.getValue(), value)) subject.next(value)\n}\n\nfunction query(\n source: MessageBusStateSource<unknown>,\n type: string,\n options: MessageBusQueryOptions | undefined,\n connectionSignal: AbortSignal,\n resetSignal: AbortSignal,\n connection: ConnectionRecord,\n): Promise<unknown> {\n const rejection = () => new MessageBusError('REFUSED', connection.rejections.get(type))\n // A rejection outranks any earlier value: it is cleared only when the host writes a new one.\n if (connection.rejections.has(type)) return Promise.reject(rejection())\n const current = source.getCurrent()\n if (current !== undefined) return Promise.resolve(current)\n\n const signal = scopeSignal(options?.signal, resetSignal, connectionSignal)\n if (signal.aborted) return Promise.reject(new MessageBusError('ABORTED'))\n const timeoutMs = options?.timeout === undefined ? DEFAULT_TIMEOUT_MS : options.timeout\n return new Promise((resolve, reject) => {\n const timer =\n timeoutMs === null\n ? undefined\n : setTimeout(() => {\n clear()\n signal?.removeEventListener('abort', onAbort)\n reject(new MessageBusError('TIMEOUT', `query(\"${type}\") timed out`))\n }, timeoutMs)\n // A rejection that arrives while waiting rejects the pending query at once.\n const rejectedSub = connection.rejected$.subscribe((rejectedType) => {\n if (rejectedType !== type) return\n clear()\n signal?.removeEventListener('abort', onAbort)\n reject(rejection())\n })\n const clear = () => {\n if (timer !== undefined) clearTimeout(timer)\n rejectedSub.unsubscribe()\n }\n const onAbort = () => {\n clear()\n reject(new MessageBusError('ABORTED'))\n }\n signal?.addEventListener('abort', onAbort, {once: true})\n void source.firstValue.then(\n (value) => {\n clear()\n signal?.removeEventListener('abort', onAbort)\n resolve(value)\n },\n (error) => {\n clear()\n signal?.removeEventListener('abort', onAbort)\n reject(error)\n },\n )\n })\n}\n\nfunction unsubscribeOnAbort(subscription: Subscription, signal: AbortSignal | undefined): void {\n if (!signal) return\n if (signal.aborted) {\n subscription.unsubscribe()\n return\n }\n signal.addEventListener('abort', () => subscription.unsubscribe(), {\n once: true,\n })\n}\n\nfunction scopeSignal(signal: AbortSignal | undefined, ...lifecycles: AbortSignal[]): AbortSignal {\n return signal ? AbortSignal.any([signal, ...lifecycles]) : AbortSignal.any(lifecycles)\n}\n\nfunction invokeResponder(\n handler: (message: MessageBusMessage<unknown, unknown>) => unknown,\n message: MessageBusMessage<unknown, unknown> & {\n [MESSAGE_BUS_PENDING_REPLY_KEY]?: PendingReply\n },\n): void {\n const pendingReply = message[MESSAGE_BUS_PENDING_REPLY_KEY]\n const fail = (error: unknown) => {\n if (pendingReply) {\n settleReply(pendingReply, {\n ok: false,\n error: new MessageBusError('HANDLER_THREW', undefined, {\n cause: error,\n }),\n })\n }\n }\n try {\n const result = handler(message)\n if (result instanceof Promise) result.catch(fail)\n } catch (error) {\n fail(error)\n }\n}\n\nfunction respond(\n registry: MessageBusRegistry,\n type: string,\n handler: (message: MessageBusMessage<unknown, unknown>) => unknown,\n options: MessageBusAbortOptions | undefined,\n appId: string,\n connectionSignal: AbortSignal,\n): void {\n const topic = registry.topics.get(type)\n if (topic?.kind === 'event' && !canRespond(registry, topic.ownership, appId)) {\n throw new MessageBusError(\n 'OWNERSHIP_MISMATCH',\n `Cannot register a handler for event topic \"${type}\" from app \"${appId}\". Only the app that owns this topic can respond to it. Other apps can send it with emit().`,\n )\n }\n\n registry.responderCounts.set(type, (registry.responderCounts.get(type) ?? 0) + 1)\n const subscription = resolveEventSubject(registry, type).subscribe((message) =>\n invokeResponder(handler, message),\n )\n subscription.add(() => {\n const count = registry.responderCounts.get(type) ?? 0\n if (count > 0) registry.responderCounts.set(type, count - 1)\n })\n unsubscribeOnAbort(\n subscription,\n scopeSignal(options?.signal, registry.resetAbort.signal, connectionSignal),\n )\n}\n\nconst bundledMigrations = () => new Map(Object.entries(topicMigrations))\n\n/**\n * Creates an isolated message bus without installing it globally and returns the host's\n * connection to it.\n * @internal\n */\nexport function createIsolatedMessageBus(\n appId: string,\n config: {\n migrations?: ReadonlyMap<string, readonly TopicMigration[]>\n } = {},\n): MessageBusHost<Topics> {\n if (!appId) throwMissingAppId()\n\n const registry: MessageBusRegistry = {\n appId,\n topics: new Map(),\n connections: new Set(),\n connected$: new Subject(),\n eventSubjects: new Map(),\n responderCounts: new Map(),\n migrations: config.migrations ?? bundledMigrations(),\n resetAbort: new AbortController(),\n generation: 0,\n }\n\n mergeTopicManifest(registry, DASHBOARD_TOPIC_MANIFEST)\n\n return createConnection(registry, {\n appId,\n migrations: config.migrations,\n }) as MessageBusHost<Topics>\n}\n\ntype TopicVersionAdapter = {\n toInstalled: (type: string, value: unknown) => unknown\n toApplication: (type: string, value: unknown) => unknown\n}\n\ntype TopicCompatibility = {\n toInstalledEmission: TopicVersionAdapter['toInstalled']\n toApplicationStateValue: TopicVersionAdapter['toApplication']\n toApplicationEventPayload: TopicVersionAdapter['toApplication']\n toInstalledEventReply: TopicVersionAdapter['toInstalled']\n toApplicationEventReply: TopicVersionAdapter['toApplication']\n}\n\ntype TopicMigrationTransform = Pick<TopicMigration, 'up' | 'down'>\n\nconst identityMigration: TopicMigrationTransform = {\n up: (value) => value,\n down: (value) => value,\n}\n\nfunction effectiveTopicVersions(\n migrations: ReadonlyMap<string, readonly TopicMigration[]>,\n): Map<string, number> {\n const versions = new Map<string, number>()\n for (const [topic, steps] of migrations) {\n let version = 1\n for (const step of steps) if (step.to > version) version = step.to\n versions.set(topic, version)\n }\n return versions\n}\n\nfunction migrationTransformAt(\n steps: readonly TopicMigration[] | undefined,\n version: number,\n select: (step: TopicMigration) => TopicMigrationTransform | undefined,\n): TopicMigrationTransform {\n const step = steps?.find((candidate) => candidate.from === version)\n return (step ? select(step) : undefined) ?? identityMigration\n}\n\nfunction migrateVersionedValue(\n steps: readonly TopicMigration[] | undefined,\n value: unknown,\n from: number,\n to: number,\n select: (step: TopicMigration) => TopicMigrationTransform | undefined,\n): unknown {\n if (from === to) return value\n\n let current = value\n if (from < to) {\n for (let version = from; version < to; version++) {\n current = migrationTransformAt(steps, version, select).up(current)\n }\n } else {\n for (let version = from; version > to; version--) {\n current = migrationTransformAt(steps, version - 1, select).down(current)\n }\n }\n return current\n}\n\nfunction createTopicCompatibility(\n installedMigrations: ReadonlyMap<string, readonly TopicMigration[]>,\n applicationMigrations: ReadonlyMap<string, readonly TopicMigration[]>,\n): TopicCompatibility {\n const installedVersions = effectiveTopicVersions(installedMigrations)\n const applicationVersions = effectiveTopicVersions(applicationMigrations)\n const applicationVersion = (type: string) => applicationVersions.get(type) ?? 1\n const installedVersion = (type: string) => installedVersions.get(type) ?? 1\n const migrationChainFor = (type: string) =>\n (applicationVersion(type) > installedVersion(type)\n ? applicationMigrations\n : installedMigrations\n ).get(type)\n const createVersionAdapter = (\n select: (step: TopicMigration) => TopicMigrationTransform | undefined,\n ): TopicVersionAdapter => ({\n toInstalled: (type, value) =>\n migrateVersionedValue(\n migrationChainFor(type),\n value,\n applicationVersion(type),\n installedVersion(type),\n select,\n ),\n toApplication: (type, value) =>\n migrateVersionedValue(\n migrationChainFor(type),\n value,\n installedVersion(type),\n applicationVersion(type),\n select,\n ),\n })\n\n const stateValueAndEventPayload = createVersionAdapter((step) => step)\n const eventReply = createVersionAdapter((step) => step.reply)\n return {\n toInstalledEmission: stateValueAndEventPayload.toInstalled,\n toApplicationStateValue: stateValueAndEventPayload.toApplication,\n toApplicationEventPayload: stateValueAndEventPayload.toApplication,\n toInstalledEventReply: eventReply.toInstalled,\n toApplicationEventReply: eventReply.toApplication,\n }\n}\n\n// Cache projections by input reference to keep state snapshots stable.\nfunction projectCurrent(input: () => unknown, project: (value: unknown) => unknown): () => unknown {\n let lastInput: unknown\n let lastOutput: unknown\n let cached = false\n return () => {\n const current = input()\n if (current === undefined) return undefined\n if (!cached || current !== lastInput) {\n lastInput = current\n lastOutput = project(current)\n cached = true\n }\n return lastOutput\n }\n}\n\n// The connection's view of one of its state boxes, in the connection's topic version.\nfunction createStateSource(\n subject: BehaviorSubject<unknown>,\n project: (value: unknown) => unknown,\n completeOn: Observable<unknown>,\n): MessageBusStateSource<unknown> {\n const getCurrent = () => {\n const current = subject.getValue()\n return current === NO_VALUE ? undefined : current\n }\n return toStateSource(\n subject.pipe(\n filter((value) => value !== NO_VALUE),\n map(project),\n takeUntil(completeOn),\n ),\n projectCurrent(getCurrent, project),\n )\n}\n\nfunction migrateEventMessage(\n message: MessageBusMessage<unknown, unknown>,\n payload: (value: unknown) => unknown,\n reply: (value: unknown) => unknown,\n): MessageBusMessage<unknown, unknown> {\n return {\n type: message.type,\n payload: payload(message.payload),\n meta: message.meta,\n reply: (value) => message.reply(reply(value)),\n reject: (reason) => message.reject(reason),\n get signal() {\n return message.signal\n },\n }\n}\n\nfunction migrateEventReply(\n result: MessageBusEmitResult<unknown>,\n project: (value: unknown) => unknown,\n): MessageBusEmitResult<unknown> {\n let projected: Promise<unknown> | undefined\n return createLazyReply(() => (projected ??= Promise.resolve(result).then(project)))\n}\n\nfunction createRejectedConnection(\n appId: string,\n connectionError: () => unknown,\n): MessageBusConnection {\n const throwConnectionError = (): never => {\n throw connectionError()\n }\n return {\n appId,\n emit: throwConnectionError,\n // `query` is typed as a Promise, so it must reject rather than throw synchronously.\n query: () => Promise.reject(connectionError()),\n subscribe: throwConnectionError,\n disconnect: () => {},\n } as unknown as MessageBusConnection\n}\n\n/**\n * Options for connecting an application to an isolated message bus.\n * @internal\n */\nexport interface ConnectApplicationToMessageBusOptions {\n /** The application ID stamped on emitted messages. */\n appId: string\n /** The federation module id stamped on emitted messages. Defaults to `appId`. */\n moduleId?: string\n /** The topic migrations supported by the application. */\n migrations?: ReadonlyMap<string, readonly TopicMigration[]>\n}\n\n/**\n * Connects an application to an isolated message bus.\n * @internal\n */\nexport function connectApplicationToMessageBus(\n installedMessageBus: MessageBus,\n config: ConnectApplicationToMessageBusOptions,\n): MessageBusConnection<Topics> {\n if (!config.appId) throwMissingAppId()\n\n const {appId} = config\n const installedProtocol = (installedMessageBus as Partial<InternalMessageBus>)[\n MESSAGE_BUS_PROTOCOL_KEY\n ]\n if (installedProtocol !== MESSAGE_BUS_PROTOCOL) {\n console.error(\n `[sanity-sdk:message-bus] protocol mismatch for \"${appId}\": installed ${String(installedProtocol)}, this copy speaks ${MESSAGE_BUS_PROTOCOL}`,\n )\n return createRejectedConnection(\n appId,\n () =>\n new MessageBusError(\n 'PROTOCOL_MISMATCH',\n `installed message bus speaks protocol ${String(installedProtocol)}, this copy speaks ${MESSAGE_BUS_PROTOCOL}`,\n ),\n )\n }\n\n const registry = (installedMessageBus as Partial<InternalMessageBus>)[MESSAGE_BUS_REGISTRY_KEY]\n if (!registry) {\n console.error(`[sanity-sdk:message-bus] incompatible message bus for \"${appId}\"`)\n return createRejectedConnection(\n appId,\n () =>\n new MessageBusError(\n 'PROTOCOL_MISMATCH',\n 'installed message bus does not expose a compatible registry',\n ),\n )\n }\n\n try {\n mergeTopicManifest(registry, DASHBOARD_TOPIC_MANIFEST)\n } catch (error) {\n console.error(`[sanity-sdk:message-bus] topic manifest conflict for \"${appId}\"`, {error})\n return createRejectedConnection(appId, () => error)\n }\n\n return createConnection(registry, config) as MessageBusConnection<Topics>\n}\n\n// Hands the host the same client object for a connection across `connections` subscriptions.\nfunction createClient(\n registry: MessageBusRegistry,\n record: ConnectionRecord,\n compatibility: TopicCompatibility,\n): MessageBusClient {\n return {\n appId: record.appId,\n moduleId: record.moduleId,\n closed: record.abort.signal,\n emit: (type: string, value: unknown) => {\n if (record.abort.signal.aborted) {\n console.warn(\n `[sanity-sdk:message-bus] \"${type}\" not written: connection \"${record.moduleId}\" has closed`,\n )\n return\n }\n emitState(registry, record, type, compatibility.toInstalledEmission(type, value))\n },\n reject: (type: string, message?: string) => {\n if (record.abort.signal.aborted) return\n record.rejections.set(type, message)\n record.rejected$.next(type)\n },\n } as MessageBusClient\n}\n\n// Open connections other than the host's own first, then each new one; one client object per\n// connection so the host can keep them in a Set. Completes when the host connection disconnects.\nfunction createConnectionsSource(\n registry: MessageBusRegistry,\n self: ConnectionRecord,\n compatibility: TopicCompatibility,\n completeOn: Observable<unknown>,\n): Observable<MessageBusClient> {\n const clients = new WeakMap<ConnectionRecord, MessageBusClient>()\n const clientFor = (record: ConnectionRecord) => {\n let client = clients.get(record)\n if (!client) {\n client = createClient(registry, record, compatibility)\n clients.set(record, client)\n }\n return client\n }\n return defer(() => concat(from([...registry.connections]), registry.connected$)).pipe(\n filter((record) => record !== self),\n map(clientFor),\n takeUntil(completeOn),\n )\n}\n\nfunction createConnection(\n registry: MessageBusRegistry,\n config: ConnectApplicationToMessageBusOptions,\n): MessageBusConnection {\n const {appId} = config\n const moduleId = config.moduleId ?? appId\n // Each connection owns its lifetime; disconnect() aborts it without touching siblings.\n const connectionAbort = new AbortController()\n const connectionSignal = connectionAbort.signal\n // ReplaySubject, not fromEvent: `abort` fires once, so a cold listener attached by a\n // stream subscribed after disconnect() would never see it and never complete. Replaying\n // the notification lets those late subscribers complete immediately.\n const connectionAborted$ = new ReplaySubject<void>(1)\n connectionSignal.addEventListener('abort', () => connectionAborted$.next(), {once: true})\n\n const record: ConnectionRecord = {\n appId,\n moduleId,\n stateSubjects: new Map(),\n rejections: new Map(),\n rejected$: new Subject<string>(),\n abort: connectionAbort,\n }\n\n const compatibility = createTopicCompatibility(\n registry.migrations,\n config.migrations ?? bundledMigrations(),\n )\n const isState = (type: string) => isStateTopic(registry, type)\n\n // Reuse topic streams because React external-store snapshots require stable references.\n const applicationStreams = new Map<string, MessageBusStateSource<unknown> | Observable<unknown>>()\n let streamGeneration = registry.generation\n const cachedStream = <T extends MessageBusStateSource<unknown> | Observable<unknown>>(\n type: string,\n create: () => T,\n ): T => {\n if (streamGeneration !== registry.generation) {\n applicationStreams.clear()\n streamGeneration = registry.generation\n }\n let stream = applicationStreams.get(type)\n if (!stream) {\n stream = create()\n applicationStreams.set(type, stream)\n }\n return stream as T\n }\n const stateSource = (type: string) =>\n cachedStream(type, () =>\n createStateSource(\n resolveStateSubject(registry, record, type),\n (value) => compatibility.toApplicationStateValue(type, value),\n connectionAborted$,\n ),\n )\n const eventStream = (type: string) =>\n cachedStream(type, () =>\n resolveEventSubject(registry, type).pipe(\n map((message) => compatibility.toApplicationEventPayload(type, message.payload)),\n takeUntil(connectionAborted$),\n ),\n )\n\n // A disconnected connection must not reach siblings, so its operations fail before touching\n // the shared registry rather than only tearing down pending requests and subscriptions.\n const throwIfDisconnected = () => {\n if (connectionSignal.aborted) throw new MessageBusError('ABORTED')\n }\n\n const connection = {\n appId,\n emit: (type: string, payload: unknown, options?: MessageBusEmitOptions) => {\n throwIfDisconnected()\n return migrateEventReply(\n emit(\n registry,\n type,\n compatibility.toInstalledEmission(type, payload),\n options,\n appId,\n moduleId,\n connectionSignal,\n ),\n (value) => compatibility.toApplicationEventReply(type, value),\n )\n },\n query: (type: string, options?: MessageBusQueryOptions) => {\n if (connectionSignal.aborted) return Promise.reject(new MessageBusError('ABORTED'))\n return query(\n stateSource(type),\n type,\n options,\n connectionSignal,\n registry.resetAbort.signal,\n record,\n )\n },\n subscribe: (\n type: string,\n handler?: (arg: never) => void,\n options?: MessageBusAbortOptions,\n ): MessageBusStateSource<unknown> | Observable<unknown> | undefined => {\n throwIfDisconnected()\n if (isState(type)) {\n const source = stateSource(type)\n if (!handler) return source\n unsubscribeOnAbort(\n source.subscribe(handler as (value: unknown) => void),\n scopeSignal(options?.signal, registry.resetAbort.signal, connectionSignal),\n )\n return undefined\n }\n if (!handler) return eventStream(type)\n respond(\n registry,\n type,\n (message) =>\n (handler as (message: MessageBusMessage<unknown, unknown>) => void)(\n migrateEventMessage(\n message,\n (value) => compatibility.toApplicationEventPayload(type, value),\n (value) => compatibility.toInstalledEventReply(type, value),\n ),\n ),\n options,\n appId,\n connectionSignal,\n )\n return undefined\n },\n disconnect: () => {\n if (connectionSignal.aborted) return\n connectionAbort.abort()\n for (const subject of record.stateSubjects.values()) subject.complete()\n record.stateSubjects.clear()\n record.rejected$.complete()\n registry.connections.delete(record)\n },\n }\n\n if (appId === registry.appId) {\n Object.assign(connection, {\n connections: createConnectionsSource(registry, record, compatibility, connectionAborted$),\n })\n }\n\n const instance = connection as unknown as InternalMessageBus\n instance[MESSAGE_BUS_REGISTRY_KEY] = registry\n instance[MESSAGE_BUS_PROTOCOL_KEY] = MESSAGE_BUS_PROTOCOL\n\n // Announce last: a host subscriber may write to the new client synchronously.\n registry.connections.add(record)\n registry.connected$.next(record)\n return instance as unknown as MessageBusConnection\n}\n\nfunction reset(registry: MessageBusRegistry): void {\n registry.resetAbort.abort()\n for (const connection of registry.connections) {\n for (const subject of connection.stateSubjects.values()) subject.complete()\n connection.stateSubjects.clear()\n connection.rejections.clear()\n }\n for (const subject of registry.eventSubjects.values()) subject.complete()\n\n registry.topics.clear()\n registry.eventSubjects.clear()\n registry.responderCounts.clear()\n registry.resetAbort = new AbortController()\n registry.generation += 1\n mergeTopicManifest(registry, DASHBOARD_TOPIC_MANIFEST)\n}\n\ndeclare const __SANITY_APP_ID__: string | undefined\n\nfunction throwMissingAppId(): never {\n throw new MessageBusError(\n 'MISSING_APP_ID',\n 'Cannot initialize the message bus without an app ID. Build the application with the Sanity CLI or pass an app ID when connecting.',\n )\n}\n\nconst resolveAppId = (appId?: string): string | undefined =>\n appId ?? (typeof __SANITY_APP_ID__ === 'string' ? __SANITY_APP_ID__ : undefined)\n\nfunction getInstalledMessageBus(): MessageBus | undefined {\n const bus = (globalThis as {[MESSAGE_BUS_KEY]?: unknown})[MESSAGE_BUS_KEY]\n return typeof bus === 'object' && bus !== null && MESSAGE_BUS_REGISTRY_KEY in bus\n ? (bus as unknown as MessageBus)\n : undefined\n}\n\n/**\n * Returns whether a message bus registry is installed.\n * @internal\n */\nexport function isMessageBusInstalled(): boolean {\n return getInstalledMessageBus() !== undefined\n}\n\n/**\n * Returns whether this application installed the message bus and hosts the others on it.\n * @internal\n */\nexport function isMessageBusHost(): boolean {\n const installedMessageBus = getInstalledMessageBus()\n return (\n !!installedMessageBus &&\n (installedMessageBus as InternalMessageBus)[MESSAGE_BUS_REGISTRY_KEY].appId === resolveAppId()\n )\n}\n\n/**\n * Returns whether this application runs on an installed message bus.\n * @internal\n */\nexport function isMessageBusEnvironment(): boolean {\n return isMessageBusInstalled()\n}\n\n/**\n * Options for connecting to an installed message bus.\n * @public\n * @category Message Bus\n */\nexport interface ConnectMessageBusOptions {\n /** The application ID. Defaults to the ID embedded by the Sanity CLI. */\n appId?: string\n /** The federation module id stamped on emitted messages. Defaults to `appId`. */\n moduleId?: string\n}\n\n/**\n * Connects to the installed message bus, or returns `undefined` when no compatible connection exists.\n * @public\n * @category Message Bus\n */\nexport function connectMessageBus(\n options: ConnectMessageBusOptions = {},\n): MessageBusConnection | undefined {\n const installedMessageBus = getInstalledMessageBus()\n if (!installedMessageBus) return undefined\n\n const appId = resolveAppId(options.appId)\n if (!appId) {\n console.warn(\n '[sanity-sdk:message-bus] cannot connect without an app ID; build with the Sanity CLI or pass appId',\n )\n return undefined\n }\n\n const connection = connectApplicationToMessageBus(installedMessageBus, {\n appId,\n moduleId: options.moduleId,\n })\n return MESSAGE_BUS_REGISTRY_KEY in connection ? connection : undefined\n}\n\n/**\n * Resets the installed message bus for test isolation.\n * @internal\n */\nexport function resetMessageBus(): void {\n const installedMessageBus = getInstalledMessageBus()\n if (!installedMessageBus) return\n reset((installedMessageBus as InternalMessageBus)[MESSAGE_BUS_REGISTRY_KEY])\n}\n\n/**\n * Options for installing the shared message bus. The host is the whole app, so it carries\n * no `moduleId`.\n * @internal\n */\nexport interface InstallMessageBusOptions {\n /** The application ID. Defaults to the ID embedded by the Sanity CLI. */\n appId?: string\n}\n\n/**\n * Installs the shared message bus and returns the host's connection, or connects to its\n * existing installation. Only the host calls this; another app's ID is rejected because the\n * connection it would get has no `connections`.\n * @internal\n */\nexport function installMessageBus(options: InstallMessageBusOptions = {}): MessageBusHost<Topics> {\n const appId = resolveAppId(options.appId) ?? throwMissingAppId()\n const installedMessageBus = getInstalledMessageBus()\n if (installedMessageBus) {\n const installedAppId = (installedMessageBus as InternalMessageBus)[MESSAGE_BUS_REGISTRY_KEY]\n .appId\n if (installedAppId !== appId) {\n throw new MessageBusError(\n 'OWNERSHIP_MISMATCH',\n `Cannot install the message bus as \"${appId}\": it is already installed by \"${installedAppId}\". Applications connect with connectMessageBus().`,\n )\n }\n return connectApplicationToMessageBus(installedMessageBus, {\n appId,\n }) as MessageBusHost<Topics>\n }\n\n const globals = globalThis as {[MESSAGE_BUS_KEY]?: MessageBus}\n if (globals[MESSAGE_BUS_KEY]) {\n // A foreign value already occupies the bus symbol (e.g. an older Workbench bus); overwriting it disconnects that bus.\n console.error(\n '[sanity-sdk:message-bus] overwriting an incompatible message bus already installed',\n )\n }\n const host = createIsolatedMessageBus(appId)\n globals[MESSAGE_BUS_KEY] = host\n return host\n}\n\n/**\n * Declares state topics that are not in the bundled manifest, with the seed a new\n * connection's box starts from.\n * @internal\n */\nexport function registerStateTopics(\n target: MessageBus,\n topics: Partial<{[K in StateTopic]: ValueOf<K> | undefined}>,\n): void {\n const registry = (target as InternalMessageBus)[MESSAGE_BUS_REGISTRY_KEY]\n const manifest: TopicManifest = Object.fromEntries(\n Object.entries(topics).map(([name, seed]) => [name, {kind: 'state', seed}]),\n )\n mergeTopicManifest(registry, manifest)\n}\n","export const DEFAULT_BASE = 'http://localhost'\nexport const AUTH_CODE_PARAM = 'sid'\nexport const DEFAULT_API_VERSION = '2021-06-07'\nexport const REQUEST_TAG_PREFIX = 'sanity.sdk.auth'\n","import {type SanityConfig} from '../config/sanityConfig'\nimport {isMessageBusEnvironment, isMessageBusHost} from '../dashboard/messageBus/bus'\nimport {DEFAULT_BASE} from './authConstants'\n\n/**\n * The runtime auth mode determines which authentication strategy the SDK uses.\n *\n * - `studio` — Running inside Sanity Studio. Token is discovered from\n * Studio's localStorage entry or via cookie auth.\n * - `oauth` — Configured with `auth.oauth`. Authenticates via Sanity's\n * OAuth 2.0 authorization-code + PKCE flow.\n * - `dashboard` — Running inside the Sanity Dashboard iframe. Token is\n * provided by the parent frame via Comlink.\n * - `standalone` — Running as an independent app. Token comes from\n * localStorage or the OAuth login flow.\n *\n * @internal\n */\ntype AuthMode = 'studio' | 'oauth' | 'dashboard' | 'standalone'\n\n/**\n * Determines the auth mode from instance config and environment.\n *\n * Priority:\n * 1. `studio` config provided → `'studio'`\n * 2. `auth.oauth` config provided → `'oauth'` (explicit config wins over\n * environment detection)\n * 3. Dashboard context detected (`_context` URL param with content) → `'dashboard'`\n * 4. Otherwise → `'standalone'`\n *\n * @internal\n */\nexport function resolveAuthMode(config: SanityConfig, locationHref: string): AuthMode {\n if (isStudioConfig(config)) return 'studio'\n if (config.auth?.oauth) return 'oauth'\n if ((isMessageBusEnvironment() && !isMessageBusHost()) || detectDashboardContext(locationHref)) {\n return 'dashboard'\n }\n return 'standalone'\n}\n\n/**\n * Returns `true` when the config indicates the SDK is running inside a Studio.\n *\n * @internal\n */\nexport function isStudioConfig(config: SanityConfig): boolean {\n return !!config.studio\n}\n\n/**\n * Checks whether the given location href contains a `_context` URL parameter\n * with a non-empty JSON object, indicating the SDK is running inside the\n * Sanity Dashboard.\n *\n * @internal\n */\nfunction detectDashboardContext(locationHref: string): boolean {\n try {\n const parsedUrl = new URL(locationHref, DEFAULT_BASE)\n const contextParam = parsedUrl.searchParams.get('_context')\n if (!contextParam) return false\n\n const parsed: unknown = JSON.parse(contextParam)\n return (\n typeof parsed === 'object' &&\n parsed !== null &&\n !Array.isArray(parsed) &&\n Object.keys(parsed as Record<string, unknown>).length > 0\n )\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('Failed to parse dashboard context from initial location:', err)\n return false\n }\n}\n","/**\n * Represents the various states the authentication type can be in.\n *\n * @public\n */\nexport enum AuthStateType {\n LOGGED_IN = 'logged-in',\n LOGGING_IN = 'logging-in',\n ERROR = 'error',\n LOGGED_OUT = 'logged-out',\n}\n","import {\n distinctUntilChanged,\n exhaustMap,\n filter,\n map,\n Observable,\n type Subscription,\n switchMap,\n takeWhile,\n timer,\n} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'\nimport {getAuthLogger} from './authLogger'\nimport {AuthStateType} from './authStateType'\nimport {type AuthState, type AuthStoreState} from './authStore'\n\nconst REFRESH_INTERVAL = 12 * 60 * 60 * 1000 // 12 hours in milliseconds\n\nfunction createTokenRefreshStream(\n token: string,\n clientFactory: AuthStoreState['options']['clientFactory'],\n apiHost: string | undefined,\n): Observable<{token: string}> {\n return new Observable((subscriber) => {\n const client = clientFactory({\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n useProjectHostname: false,\n useCdn: false,\n token,\n ignoreBrowserTokenWarning: true,\n ...(apiHost && {apiHost}),\n })\n\n const subscription = client.observable\n .request<{token: string}>({\n url: 'auth/refresh-token',\n method: 'POST',\n tag: 'refresh-token',\n body: {\n token,\n },\n })\n .subscribe(subscriber)\n\n return () => subscription.unsubscribe()\n })\n}\n\nfunction shouldRefreshToken(lastRefresh: number | undefined): boolean {\n if (!lastRefresh) return true\n const timeSinceLastRefresh = Date.now() - lastRefresh\n return timeSinceLastRefresh >= REFRESH_INTERVAL\n}\n\n/**\n * Periodically refreshes stamped auth tokens (those containing `-st`).\n *\n * Two triggers cause a refresh while the user stays logged in:\n * - a 12-hour interval timer (only fires while the tab is visible)\n * - the tab becoming visible again after `lastTokenRefresh` has gone stale\n *\n * Non-stamped tokens (e.g. personal access tokens) are never refreshed.\n *\n * @internal\n */\nexport const refreshStampedToken = ({\n state,\n instance,\n}: StoreContext<AuthStoreState>): Subscription => {\n const logger = getAuthLogger(instance)\n\n const {clientFactory, apiHost, storageArea, storageKey} = state.get().options\n\n const refreshToken$ = state.observable.pipe(\n map((storeState) => storeState.authState),\n filter(\n (authState): authState is Extract<AuthState, {type: AuthStateType.LOGGED_IN}> =>\n authState.type === AuthStateType.LOGGED_IN,\n ),\n distinctUntilChanged((prev, curr) => prev.token === curr.token),\n filter((authState) => authState.token.includes('-st')), // Ensure we only try to refresh stamped tokens\n exhaustMap(() =>\n new Observable<{token: string}>((subscriber) => {\n const visibilityHandler = () => {\n const currentState = state.get()\n if (\n document.visibilityState === 'visible' &&\n currentState.authState.type === AuthStateType.LOGGED_IN &&\n shouldRefreshToken(currentState.authState.lastTokenRefresh)\n ) {\n createTokenRefreshStream(\n currentState.authState.token,\n clientFactory,\n apiHost,\n ).subscribe({\n next: (response) => {\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {\n ...prev.authState,\n token: response.token,\n lastTokenRefresh: Date.now(),\n }\n : prev.authState,\n }))\n subscriber.next(response)\n },\n error: (error) => subscriber.error(error),\n })\n }\n }\n\n const timerSubscription = timer(REFRESH_INTERVAL, REFRESH_INTERVAL)\n .pipe(\n filter(() => document.visibilityState === 'visible'),\n switchMap(() => {\n const currentState = state.get().authState\n if (currentState.type !== AuthStateType.LOGGED_IN) {\n throw new Error('User logged out before refresh could complete')\n }\n return createTokenRefreshStream(currentState.token, clientFactory, apiHost)\n }),\n )\n .subscribe({\n next: (response) => {\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {\n ...prev.authState,\n token: response.token,\n lastTokenRefresh: Date.now(),\n }\n : prev.authState,\n }))\n subscriber.next(response)\n },\n error: (error) => subscriber.error(error),\n })\n\n document.addEventListener('visibilitychange', visibilityHandler)\n\n return () => {\n document.removeEventListener('visibilitychange', visibilityHandler)\n timerSubscription.unsubscribe()\n }\n }).pipe(\n takeWhile(() => state.get().authState.type === AuthStateType.LOGGED_IN),\n map((response: {token: string}) => ({token: response.token})),\n ),\n ),\n )\n\n return refreshToken$.subscribe({\n next: (response: {token: string}) => {\n logger.debug('Token refresh completed, updating state')\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {\n ...prev.authState,\n token: response.token,\n lastTokenRefresh: Date.now(),\n }\n : prev.authState,\n }))\n storageArea?.setItem(storageKey, JSON.stringify({token: response.token}))\n },\n error: (error) => {\n logger.error('Token refresh failed', {error})\n state.set('setRefreshStampedTokenError', {authState: {type: AuthStateType.ERROR, error}})\n },\n })\n}\n","import {type CurrentUser} from '@sanity/types'\nimport {\n catchError,\n distinctUntilChanged,\n EMPTY,\n filter,\n map,\n type Subscription,\n switchMap,\n} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'\nimport {getAuthLogger} from './authLogger'\nimport {isStudioConfig} from './authMode'\nimport {AuthStateType} from './authStateType'\nimport {type AuthMethodOptions, type AuthState, type AuthStoreState} from './authStore'\n\n/**\n * Subscribes to auth state changes and fetches the current user when\n * the state transitions to `LOGGED_IN` without a `currentUser`.\n *\n * @param context - The store context for the auth store.\n * @param fetchOptions - Configuration options. When `useProjectHostname` is\n * `true`, requests use the project-specific hostname (required for Studio\n * cookie auth). Set to `true` for studio mode, `false` otherwise.\n *\n * @internal\n */\nexport const subscribeToStateAndFetchCurrentUser = (\n {state, instance}: StoreContext<AuthStoreState>,\n fetchOptions?: {useProjectHostname?: boolean},\n): Subscription => {\n const logger = getAuthLogger(instance)\n\n const {clientFactory, apiHost} = state.get().options\n const useProjectHostname = fetchOptions?.useProjectHostname ?? isStudioConfig(instance.config)\n const projectId = instance.config.projectId\n\n const currentUser$ = state.observable\n .pipe(\n map(({authState, options: storeOptions}) => ({\n authState,\n authMethod: storeOptions.authMethod,\n })),\n filter(\n (\n value,\n ): value is {\n authState: Extract<AuthState, {type: AuthStateType.LOGGED_IN}>\n authMethod: AuthMethodOptions\n } => value.authState.type === AuthStateType.LOGGED_IN && !value.authState.currentUser,\n ),\n map((value) => ({token: value.authState.token, authMethod: value.authMethod})),\n distinctUntilChanged(\n (prev, curr) => prev.token === curr.token && prev.authMethod === curr.authMethod,\n ),\n )\n .pipe(\n map(({token, authMethod}) =>\n clientFactory({\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n token: authMethod === 'cookie' ? undefined : token,\n ignoreBrowserTokenWarning: true,\n useProjectHostname,\n useCdn: false,\n ...(authMethod === 'cookie' ? {withCredentials: true} : {}),\n ...(useProjectHostname && projectId ? {projectId} : {}),\n ...(apiHost && {apiHost}),\n }),\n ),\n switchMap((client) =>\n client.observable\n .request<CurrentUser>({\n url: '/users/me',\n method: 'GET',\n tag: 'users.get-current',\n })\n .pipe(\n /**\n * Catch inside switchMap so the outer subscription survives.\n * Without this, a 401 terminates the subscription permanently\n * and subsequent token refreshes via comlink never re-fetch /users/me.\n * @see SDK-1409\n */\n catchError((error) => {\n logger.error('Failed to fetch current user', {error})\n state.set('setError', {authState: {type: AuthStateType.ERROR, error}})\n return EMPTY\n }),\n ),\n ),\n )\n\n return currentUser$.subscribe({\n next: (currentUser) => {\n logger.info('Current user fetched successfully', {\n hasEmail: !!currentUser.email,\n })\n // userId is PII, so only surface it at debug level\n logger.debug('Current user details', {userId: currentUser.id})\n state.set('setCurrentUser', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {...prev.authState, currentUser}\n : prev.authState,\n }))\n },\n })\n}\n","import {type ClientError} from '@sanity/client'\nimport {type CurrentUser} from '@sanity/types'\nimport {EMPTY, fromEvent, Observable} from 'rxjs'\n\nimport {AUTH_CODE_PARAM, DEFAULT_BASE} from './authConstants'\nimport {AuthStateType} from './authStateType'\nimport {type LoggedInAuthState} from './authStore'\n\n/**\n * Creates a properly initialized {@link LoggedInAuthState}.\n *\n * For stamped tokens (containing `\"-st\"`), `lastTokenRefresh` is set to\n * `Date.now()` so that the visibility-change handler in\n * {@link refreshStampedToken} does not trigger an unnecessary refresh the\n * first time the tab becomes visible.\n *\n * @param token - The auth token.\n * @param currentUser - The current user, or `null` if not yet fetched.\n * @param existingLastTokenRefresh - An existing timestamp to preserve\n * (e.g. when updating a token while keeping the previous refresh time).\n * @internal\n */\nexport function createLoggedInAuthState(\n token: string,\n currentUser: CurrentUser | null,\n existingLastTokenRefresh?: number,\n): LoggedInAuthState {\n const isStampedToken = token.includes('-st')\n const lastTokenRefresh = existingLastTokenRefresh ?? (isStampedToken ? Date.now() : undefined)\n\n return {\n type: AuthStateType.LOGGED_IN,\n token,\n currentUser,\n ...(lastTokenRefresh !== undefined && {lastTokenRefresh}),\n }\n}\n\nexport function getAuthCode(callbackUrl: string | undefined, locationHref: string): string | null {\n const loc = new URL(locationHref, DEFAULT_BASE)\n const callbackLocation = callbackUrl ? new URL(callbackUrl, DEFAULT_BASE) : undefined\n const callbackLocationMatches = callbackLocation\n ? loc.pathname.toLowerCase().startsWith(callbackLocation.pathname.toLowerCase())\n : true\n\n // First, try getting the auth code (sid) from hash or search params directly\n let authCode =\n new URLSearchParams(loc.hash.slice(1)).get(AUTH_CODE_PARAM) ||\n new URLSearchParams(loc.search).get(AUTH_CODE_PARAM)\n\n // If not found directly, try extracting it from the _context parameter as a fallback\n if (!authCode) {\n const contextParam = new URLSearchParams(loc.search).get('_context')\n if (contextParam) {\n try {\n const parsedContext = JSON.parse(contextParam)\n if (\n parsedContext &&\n typeof parsedContext === 'object' &&\n typeof parsedContext.sid === 'string' &&\n parsedContext.sid // Ensure it's not an empty string\n ) {\n authCode = parsedContext.sid\n }\n } catch {\n // Silently ignore _context JSON parsing errors; authCode remains null/empty\n }\n }\n }\n\n return authCode && callbackLocationMatches ? authCode : null\n}\n\nexport function getTokenFromLocation(locationHref: string): string | null {\n const loc = new URL(locationHref)\n const token = new URLSearchParams(loc.hash.slice(1)).get('token')\n return token ? token : null\n}\n\n/**\n * Attempts to retrieve a token from the configured storage.\n * If invalid or not present, returns null.\n */\nexport function getTokenFromStorage(\n storageArea: Storage | undefined,\n storageKey: string,\n): string | null {\n if (!storageArea) return null\n const item = storageArea.getItem(storageKey)\n if (item === null) return null\n\n try {\n const parsed: unknown = JSON.parse(item)\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n !('token' in parsed) ||\n typeof parsed.token !== 'string'\n ) {\n throw new Error('Invalid stored auth data structure')\n }\n return parsed.token\n } catch {\n storageArea.removeItem(storageKey)\n return null\n }\n}\n\n/**\n * Creates an observable stream of storage events. If not in a browser environment,\n * returns an EMPTY observable.\n */\nexport function getStorageEvents(): Observable<StorageEvent> {\n const isBrowser = typeof window !== 'undefined' && typeof window.addEventListener === 'function'\n\n if (!isBrowser) {\n return EMPTY\n }\n\n return fromEvent<StorageEvent>(window, 'storage')\n}\n\n/**\n * Returns a default storage instance (localStorage) if available.\n * If not available or an error occurs, returns undefined.\n */\nexport function getDefaultStorage(): Storage | undefined {\n try {\n if (typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function') {\n return localStorage\n }\n return undefined\n } catch {\n return undefined\n }\n}\n\n/**\n * Returns the default location to use.\n * Tries accessing `location.href`, falls back to a default base if not available or on error.\n */\nexport function getDefaultLocation(): string {\n try {\n if (typeof location === 'undefined') return DEFAULT_BASE\n if (typeof location.href === 'string') return location.href\n return DEFAULT_BASE\n } catch {\n return DEFAULT_BASE\n }\n}\n\n/**\n * Cleans up the URL by removing the `token` from the hash and the `sid` and `url` search params.\n * @internal\n */\nexport function getCleanedUrl(locationUrl: string): string {\n const loc = new URL(locationUrl)\n // Remove only the `token` param from the hash while preserving other fragments\n const rawHash = loc.hash.startsWith('#') ? loc.hash.slice(1) : loc.hash\n if (rawHash && rawHash.includes('=')) {\n const hashParams = new URLSearchParams(rawHash)\n hashParams.delete('token')\n hashParams.delete('withSid')\n const nextHash = hashParams.toString()\n loc.hash = nextHash ? `#${nextHash}` : ''\n }\n loc.searchParams.delete('sid')\n loc.searchParams.delete('url')\n return loc.toString()\n}\n\n// -----------------------------------------------------------------------------\n// ClientError helpers (shared)\n// -----------------------------------------------------------------------------\n\n/** @internal */\nexport type ApiErrorBody = {\n error?: {type?: string; description?: string; projectID?: unknown; userID?: unknown}\n type?: string\n description?: string\n message?: string\n}\n\n/** @internal Extracts the structured API error body from a ClientError, if present. */\nexport function getClientErrorApiBody(error: ClientError): ApiErrorBody | undefined {\n const body: unknown = (error as ClientError).response?.body\n return body && typeof body === 'object' ? (body as ApiErrorBody) : undefined\n}\n\n/** @internal Returns the error type string from an API error body, if available. */\nexport function getClientErrorApiType(error: ClientError): string | undefined {\n const body = getClientErrorApiBody(error)\n return body?.error?.type ?? body?.type\n}\n\n/**\n * Returns the project an API error refers to, if available.\n * @internal\n */\nexport function getClientErrorApiProjectId(error: ClientError): string | undefined {\n const projectId = getClientErrorApiBody(error)?.error?.projectID\n return typeof projectId === 'string' && projectId ? projectId : undefined\n}\n","import {type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {DEFAULT_BASE} from './authConstants'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState, type DashboardContext} from './authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from './authStrategy'\nimport {refreshStampedToken} from './refreshStampedToken'\nimport {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'\nimport {createLoggedInAuthState, getAuthCode, getTokenFromLocation} from './utils'\n\n/**\n * Parses the dashboard context from a location href's `_context` URL parameter.\n * Strips the `sid` property from the parsed context (it's handled separately).\n *\n * @internal\n */\nfunction parseDashboardContext(locationHref: string): DashboardContext {\n try {\n const parsedUrl = new URL(locationHref, DEFAULT_BASE)\n const contextParam = parsedUrl.searchParams.get('_context')\n if (contextParam) {\n const parsedContext = JSON.parse(contextParam)\n\n if (\n parsedContext &&\n typeof parsedContext === 'object' &&\n !Array.isArray(parsedContext) &&\n Object.keys(parsedContext).length > 0\n ) {\n // Explicitly remove the 'sid' property before assigning\n delete parsedContext.sid\n return parsedContext as DashboardContext\n }\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('Failed to parse dashboard context from initial location:', err)\n }\n return {} // Empty dashboard context if parsing fails\n}\n\n/**\n * Resolves the initial auth state for Dashboard mode.\n *\n * In dashboard mode the token is provided by the parent frame via Comlink,\n * so the SDK starts in a `LOGGED_OUT` state and waits for the token to arrive.\n * The `_context` URL parameter provides dashboard metadata (orgId, mode, env).\n *\n * A provided token (`auth.token`) or an auth code/callback still takes\n * precedence, even when running inside the dashboard.\n *\n * @internal\n */\nexport function getDashboardInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, initialLocationHref} = options\n const providedToken = authConfig.token\n const callbackUrl = authConfig.callbackUrl\n const storageKey = '__sanity_auth_token'\n\n const dashboardContext = parseDashboardContext(initialLocationHref)\n\n // Dashboard does NOT use localStorage — token comes from the parent frame\n const storageArea = undefined\n\n // Provided token always wins, even in dashboard\n if (providedToken) {\n return {\n authState: createLoggedInAuthState(providedToken, null),\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext,\n }\n }\n\n // Check for auth code or token-from-location (callback handling)\n if (getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref)) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext,\n }\n }\n\n // Default: logged out, waiting for Comlink to provide token\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext,\n }\n}\n\n/**\n * Initialize Dashboard auth subscriptions:\n * - Subscribe to state changes and fetch current user\n * - Start stamped token refresh\n *\n * Note: storage events are NOT subscribed in dashboard mode since\n * the dashboard does not use localStorage for token persistence.\n *\n * @internal\n */\nexport function initializeDashboardAuth(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n let startedRefresher = false\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: false}))\n\n // Dashboard does not subscribe to storage events\n\n if (!tokenRefresherRunning) {\n startedRefresher = true\n subscriptions.push(refreshStampedToken(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: startedRefresher,\n }\n}\n","import {type SanityClient} from '@sanity/client'\n\nimport {REQUEST_TAG_PREFIX} from '../authConstants'\nimport {type AuthStoreState} from '../authStore'\nimport {type OAuthTokens} from './types'\n\n/** The token endpoint's JSON response shape. */\nexport interface TokenEndpointResponse {\n access_token: string\n token_type: string\n expires_in: number\n refresh_token?: string\n}\n\ntype AuthOptions = AuthStoreState['options']\n\n/** Auth store options narrowed to an instance configured for OAuth. */\nexport type ConfiguredOAuthOptions = AuthOptions & {oauth: NonNullable<AuthOptions['oauth']>}\n\n/** Builds the RFC 8707 resource indicator for an organisation. */\nfunction getResourceIndicator(organizationId: string): string {\n return `urn:io.sanity:organization:${organizationId}`\n}\n\n/**\n * Appends the RFC 8707 `resource` indicator to `params` when an organisation\n * id is configured. Without one, the request is left unscoped.\n */\nexport function appendResourceIndicator(\n params: URLSearchParams,\n oauth: ConfiguredOAuthOptions['oauth'],\n): void {\n if (oauth.organizationId) {\n params.append('resource', getResourceIndicator(oauth.organizationId))\n }\n}\n\n/**\n * Serialises tokens for storage, converting `expiresAt` to an ISO string.\n *\n * @internal\n */\nexport function serializeTokens(tokens: OAuthTokens): string {\n return JSON.stringify({\n accessToken: tokens.accessToken,\n tokenType: tokens.tokenType,\n expiresIn: tokens.expiresIn,\n expiresAt: tokens.expiresAt.toISOString(),\n ...(tokens.refreshToken !== undefined && {refreshToken: tokens.refreshToken}),\n })\n}\n\n/**\n * Reads the store options, throwing when the instance was not configured for\n * OAuth.\n */\nexport function getOAuthOptions(state: AuthStoreState): ConfiguredOAuthOptions {\n const {options} = state\n if (!options.oauth) {\n throw new Error('OAuth is not configured on this instance (missing `auth.oauth`).')\n }\n return options as ConfiguredOAuthOptions\n}\n\n/** Creates a client for the (unauthenticated) public OAuth token/revoke calls. */\nexport function createOAuthClient(options: AuthOptions): SanityClient {\n return options.clientFactory({\n apiVersion: 'v1',\n requestTagPrefix: REQUEST_TAG_PREFIX,\n useProjectHostname: false,\n useCdn: false,\n ...(options.apiHost && {apiHost: options.apiHost}),\n })\n}\n\n/** POSTs form-encoded params to the OAuth token endpoint. */\nexport function postTokenRequest(\n client: SanityClient,\n params: URLSearchParams,\n tag: string,\n): Promise<TokenEndpointResponse> {\n return client.request<TokenEndpointResponse>({\n method: 'POST',\n url: '/auth/oauth/token',\n headers: {'content-type': 'application/x-www-form-urlencoded'},\n body: params.toString(),\n tag,\n })\n}\n\n/** Converts a token endpoint response to the {@link OAuthTokens} shape. */\nexport function toOAuthTokens(response: TokenEndpointResponse): OAuthTokens {\n return {\n accessToken: response.access_token,\n tokenType: 'bearer',\n expiresIn: response.expires_in,\n expiresAt: new Date(Date.now() + response.expires_in * 1000),\n ...(response.refresh_token !== undefined && {refreshToken: response.refresh_token}),\n }\n}\n","import {ClientError} from '@sanity/client'\n\nimport {type StoreContext} from '../../store/defineStore'\nimport {getAuthLogger} from '../authLogger'\nimport {AuthStateType} from '../authStateType'\nimport {type AuthStoreState} from '../authStore'\nimport {createLoggedInAuthState} from '../utils'\nimport {\n appendResourceIndicator,\n createOAuthClient,\n getOAuthOptions,\n postTokenRequest,\n serializeTokens,\n toOAuthTokens,\n} from './oauthClient'\nimport {type OAuthTokens} from './types'\n\n/**\n * A refresh failure is unrecoverable only when the token endpoint rejects the\n * refresh token itself (a 4xx). Rate-limit (429) and request-timeout (408)\n * responses, 5xx errors and network failures are transient, so the session is\n * kept intact for the caller to retry rather than forcing a logout.\n */\nfunction isUnrecoverableRefreshError(error: unknown): boolean {\n return error instanceof ClientError && error.statusCode !== 408 && error.statusCode !== 429\n}\n\n// Single-flight refresh shared across concurrent callers. Safe as a module\n// singleton because `authStore` is a global store (one shared state).\n// ponytail: module-level single-flight; upgrade to per-store keying only if\n// the auth store ever stops being global.\nlet refreshInFlight: Promise<Omit<OAuthTokens, 'refreshToken'> | null> | null = null\n\n/**\n * Refreshes the OAuth tokens using the `refresh_token` grant. Concurrent\n * callers share a single in-flight request. An unrecoverable failure (a 4xx\n * rejecting the refresh token) clears the tokens and transitions to\n * `LOGGED_OUT`; transient failures (network, 5xx, rate limits) leave the\n * session intact and rethrow so the caller can retry. The resolved tokens omit\n * the refresh token, which core retains internally for subsequent refreshes.\n *\n * Lives outside `oauthActions` so the auth store's initialisation path can\n * call it without importing the bound actions (which import the store).\n *\n * @internal\n */\nexport function runOAuthTokenRefresh(\n context: StoreContext<AuthStoreState>,\n): Promise<Omit<OAuthTokens, 'refreshToken'> | null> {\n if (refreshInFlight) return refreshInFlight\n refreshInFlight = doRefreshOAuthTokens(context).finally(() => {\n refreshInFlight = null\n })\n return refreshInFlight\n}\n\nasync function doRefreshOAuthTokens({\n state,\n instance,\n}: StoreContext<AuthStoreState>): Promise<Omit<OAuthTokens, 'refreshToken'> | null> {\n const logger = getAuthLogger(instance)\n const options = getOAuthOptions(state.get())\n\n const current = state.get().oauthTokens\n if (!current?.refreshToken) {\n logger.warn('No refresh token available — logging out')\n options.storageArea?.removeItem(options.storageKey)\n state.set('oauthRefreshNoToken', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n oauthTokens: undefined,\n })\n return null\n }\n\n try {\n const client = createOAuthClient(options)\n const params = new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: current.refreshToken,\n client_id: options.oauth.clientId,\n })\n appendResourceIndicator(params, options.oauth)\n const response = await postTokenRequest(client, params, 'oauth.refresh')\n\n const tokens = toOAuthTokens(response)\n if (!tokens.refreshToken) tokens.refreshToken = current.refreshToken\n\n options.storageArea?.setItem(options.storageKey, serializeTokens(tokens))\n logger.info('OAuth tokens refreshed')\n state.set('oauthRefreshed', {\n authState: createLoggedInAuthState(tokens.accessToken, null),\n oauthTokens: tokens,\n })\n const {refreshToken: _refreshToken, ...publicTokens} = tokens\n return publicTokens\n } catch (error) {\n if (!isUnrecoverableRefreshError(error)) {\n // Transient (network / 5xx / rate limit) — keep the session so the\n // caller can retry instead of forcing a logout.\n logger.warn('OAuth token refresh failed — keeping session for retry', {error})\n throw error\n }\n logger.error('OAuth token refresh failed — logging out', {error})\n options.storageArea?.removeItem(options.storageKey)\n state.set('oauthRefreshFailed', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n oauthTokens: undefined,\n })\n throw error\n }\n}\n","import {defer, distinctUntilChanged, filter, map, type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../../store/defineStore'\nimport {DEFAULT_BASE} from '../authConstants'\nimport {AuthStateType} from '../authStateType'\nimport {type AuthStoreState} from '../authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from '../authStrategy'\nimport {subscribeToStateAndFetchCurrentUser} from '../subscribeToStateAndFetchCurrentUser'\nimport {createLoggedInAuthState, getDefaultStorage, getStorageEvents} from '../utils'\nimport {runOAuthTokenRefresh} from './oauthRefresh'\nimport {type OAuthTokens} from './types'\n\n/** localStorage (or configured `storageArea`) key for persisted OAuth tokens. */\nexport const OAUTH_TOKENS_KEY = '__sanity_oauth_tokens'\n\n/** The persisted JSON shape of {@link OAuthTokens}, `expiresAt` as an ISO string. */\ninterface SerializedOAuthTokens extends Omit<OAuthTokens, 'expiresAt'> {\n expiresAt: string\n}\n\n/**\n * Parses persisted token JSON back into {@link OAuthTokens}. Returns `null`\n * when the value is missing or malformed, including an `expiresAt` that does\n * not parse to a valid date (an `Invalid Date` would otherwise read as never\n * expiring, since `NaN <= now` is always `false`).\n *\n * @internal\n */\nexport function deserializeTokens(raw: string | null): OAuthTokens | null {\n if (!raw) return null\n try {\n const parsed: unknown = JSON.parse(raw)\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n !('accessToken' in parsed) ||\n typeof (parsed as SerializedOAuthTokens).accessToken !== 'string' ||\n !('expiresAt' in parsed) ||\n typeof (parsed as SerializedOAuthTokens).expiresAt !== 'string'\n ) {\n return null\n }\n const value = parsed as SerializedOAuthTokens\n const expiresAt = new Date(value.expiresAt)\n if (Number.isNaN(expiresAt.getTime())) return null\n return {\n accessToken: value.accessToken,\n tokenType: 'bearer',\n expiresIn: value.expiresIn,\n expiresAt,\n ...(value.refreshToken !== undefined && {refreshToken: value.refreshToken}),\n }\n } catch {\n return null\n }\n}\n\n/**\n * Reads the persisted tokens, discarding entries that can never lead to a\n * session: corrupt JSON, or an expired access token with no refresh token.\n * Dropping them from storage stops them shadowing a fresh login.\n */\nfunction readPersistedTokens(\n storageArea: Storage | undefined,\n): {tokens: OAuthTokens; expired: boolean} | null {\n const raw = storageArea?.getItem(OAUTH_TOKENS_KEY) ?? null\n const tokens = deserializeTokens(raw)\n const expired = tokens !== null && tokens.expiresAt.getTime() <= Date.now()\n if (tokens && (!expired || tokens.refreshToken)) return {tokens, expired}\n if (raw) storageArea?.removeItem(OAUTH_TOKENS_KEY)\n return null\n}\n\n/**\n * Resolves the initial auth state for OAuth mode.\n *\n * State discovery order:\n * 1. Persisted tokens in `__sanity_oauth_tokens` → `LOGGED_IN`, or\n * `LOGGING_IN` when the access token has expired but a refresh token is\n * available (`initializeOauthAuth` then refreshes). Corrupt or expired\n * tokens without a refresh token are discarded.\n * 2. Callback URL (contains `code` or `error` and matches `redirectUri`)\n * → `LOGGING_IN`\n * 3. Otherwise → `LOGGED_OUT`\n *\n * @internal\n */\nexport function getOauthInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, initialLocationHref} = options\n const storageKey = OAUTH_TOKENS_KEY\n const storageArea = authConfig.storageArea ?? getDefaultStorage()\n const redirectUri = authConfig.oauth?.redirectUri\n\n // Persisted tokens win\n const persisted = readPersistedTokens(storageArea)\n if (persisted) {\n const {tokens, expired} = persisted\n return {\n // An expired token is not usable yet; `isExchangingToken` also makes\n // handleOAuthCallback stand down until the refresh has settled.\n authState: expired\n ? {type: AuthStateType.LOGGING_IN, isExchangingToken: true}\n : createLoggedInAuthState(tokens.accessToken, null),\n storageKey,\n storageArea,\n authMethod: 'localstorage',\n dashboardContext: {},\n oauthTokens: tokens,\n }\n }\n\n // Callback URL with code/error whose origin + pathname match our redirect\n // URI (query and hash are ignored). `state` alone is not a callback: the\n // server always sends `code` or `error`, and handleOAuthCallback would\n // otherwise leave the app stuck in LOGGING_IN.\n const {searchParams} = new URL(initialLocationHref, DEFAULT_BASE)\n const isCallback = searchParams.has('code') || searchParams.has('error')\n if (redirectUri && isCallback) {\n const loc = new URL(initialLocationHref, DEFAULT_BASE)\n const redirect = new URL(redirectUri, DEFAULT_BASE)\n if (loc.origin === redirect.origin && loc.pathname === redirect.pathname) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n }\n\n // No tokens, not a callback\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n}\n\n/**\n * Subscribes to cross-tab `storage` events for the OAuth tokens key, syncing\n * this tab's auth state when tokens change in another tab.\n *\n * @internal\n */\nexport function subscribeToOAuthStorageEvents({state}: StoreContext<AuthStoreState>): Subscription {\n const {storageArea} = state.get().options\n\n const tokens$ = defer(getStorageEvents).pipe(\n filter((e) => e.storageArea === storageArea && e.key === OAUTH_TOKENS_KEY),\n map(() => deserializeTokens(storageArea?.getItem(OAUTH_TOKENS_KEY) ?? null)),\n distinctUntilChanged((a, b) => a?.accessToken === b?.accessToken),\n )\n\n return tokens$.subscribe((tokens) => {\n state.set('updateOAuthTokensFromStorageEvent', {\n authState: tokens\n ? createLoggedInAuthState(tokens.accessToken, null)\n : {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n oauthTokens: tokens ?? undefined,\n })\n })\n}\n\n/**\n * Initialize OAuth auth subscriptions:\n * - Refresh persisted tokens that expired while the app was closed\n * - Subscribe to state changes and fetch current user\n * - Subscribe to cross-tab storage events for the OAuth tokens key\n *\n * OAuth tokens are refreshed via the `refresh_token` grant (see\n * `refreshOAuthTokens`), so the stamped-token refresher is not started here.\n *\n * @internal\n */\nexport function initializeOauthAuth(context: StoreContext<AuthStoreState>): {\n dispose: () => void\n tokenRefresherStarted: boolean\n} {\n const subscriptions: Subscription[] = []\n\n const {authState, oauthTokens, options} = context.state.get()\n if (authState.type === AuthStateType.LOGGING_IN && oauthTokens) {\n // getOauthInitialState handed us expired tokens with a refresh token.\n // Unrecoverable failures already end in LOGGED_OUT; a transient one is\n // surfaced rather than leaving the app stuck in LOGGING_IN.\n runOAuthTokenRefresh(context).catch((error) => {\n context.state.set('oauthStartupRefreshError', {\n authState: {type: AuthStateType.ERROR, error},\n })\n })\n }\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: false}))\n\n const storageArea = options?.storageArea\n if (storageArea) {\n subscriptions.push(subscribeToOAuthStorageEvents(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: false,\n }\n}\n","import {defer, distinctUntilChanged, filter, map, type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState} from './authStore'\nimport {createLoggedInAuthState, getStorageEvents, getTokenFromStorage} from './utils'\n\nexport const subscribeToStorageEventsAndSetToken = ({\n state,\n}: StoreContext<AuthStoreState>): Subscription => {\n const {storageArea, storageKey} = state.get().options\n\n const tokenFromStorage$ = defer(getStorageEvents).pipe(\n filter(\n (e): e is StorageEvent & {newValue: string} =>\n e.storageArea === storageArea && e.key === storageKey,\n ),\n map(() => getTokenFromStorage(storageArea, storageKey)),\n distinctUntilChanged(),\n )\n\n return tokenFromStorage$.subscribe((token) => {\n state.set('updateTokenFromStorageEvent', {\n authState: token\n ? createLoggedInAuthState(token, null)\n : {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n })\n })\n}\n","import {type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState} from './authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from './authStrategy'\nimport {refreshStampedToken} from './refreshStampedToken'\nimport {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'\nimport {subscribeToStorageEventsAndSetToken} from './subscribeToStorageEventsAndSetToken'\nimport {\n createLoggedInAuthState,\n getAuthCode,\n getDefaultStorage,\n getTokenFromLocation,\n getTokenFromStorage,\n} from './utils'\n\n/**\n * Resolves the initial auth state for Standalone mode.\n *\n * Token discovery order:\n * 1. Provided token (`auth.token` in config)\n * 2. Auth code or token from location (OAuth callback)\n * 3. localStorage: `__sanity_auth_token`\n * 4. Falls back to `LOGGED_OUT`\n *\n * @internal\n */\nexport function getStandaloneInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, initialLocationHref} = options\n const providedToken = authConfig.token\n const callbackUrl = authConfig.callbackUrl\n const storageKey = '__sanity_auth_token'\n const storageArea = authConfig.storageArea ?? getDefaultStorage()\n\n // Provided token always wins\n if (providedToken) {\n return {\n authState: createLoggedInAuthState(providedToken, null),\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n\n // Check for auth code or token-from-location (OAuth callback)\n if (getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref)) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n\n // Try localStorage\n const token = getTokenFromStorage(storageArea, storageKey)\n if (token) {\n return {\n authState: createLoggedInAuthState(token, null),\n storageKey,\n storageArea,\n authMethod: 'localstorage',\n dashboardContext: {},\n }\n }\n\n // No token found\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n}\n\n/**\n * Initialize Standalone auth subscriptions:\n * - Subscribe to state changes and fetch current user\n * - Subscribe to storage events for token key\n * - Start stamped token refresh\n *\n * @internal\n */\nexport function initializeStandaloneAuth(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n let startedRefresher = false\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: false}))\n\n const storageArea = context.state.get().options?.storageArea\n if (storageArea) {\n subscriptions.push(subscribeToStorageEventsAndSetToken(context))\n }\n\n if (!tokenRefresherRunning) {\n startedRefresher = true\n subscriptions.push(refreshStampedToken(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: startedRefresher,\n }\n}\n","import {type ClientConfig, type SanityClient} from '@sanity/client'\n\nimport {REQUEST_TAG_PREFIX} from './authConstants'\nimport {getTokenFromStorage} from './utils'\n\n/**\n * Cookie auth is a best-effort probe — if the API doesn't respond quickly,\n * the user likely isn't cookie-authenticated and we should move on rather\n * than block the auth flow indefinitely.\n */\nconst COOKIE_AUTH_TIMEOUT_MS = 10_000\n\n/**\n * Attempts to check for cookie auth by making a withCredentials request to the users endpoint.\n * @param projectId - The project ID to check for cookie auth.\n * @param clientFactory - A factory function that creates a Sanity client.\n * @returns True if the user is authenticated, false otherwise.\n * @internal\n */\nexport async function checkForCookieAuth(\n projectId: string | undefined,\n clientFactory: (config: ClientConfig) => SanityClient,\n): Promise<boolean> {\n if (!projectId) return false\n try {\n const client = clientFactory({\n projectId,\n useCdn: false,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n timeout: COOKIE_AUTH_TIMEOUT_MS,\n })\n const user = await client.request({\n url: '/users/me',\n withCredentials: true,\n tag: 'users.get-current',\n })\n return user != null && typeof user === 'object' && typeof user.id === 'string'\n } catch {\n return false\n }\n}\n\n/**\n * Attempts to retrieve a studio token from local storage.\n * @param storageArea - The storage area to retrieve the token from.\n * @param storageKey - The storage key to retrieve the token from.\n * @returns The studio token or null if it does not exist.\n * @internal\n */\nexport function getStudioTokenFromLocalStorage(\n storageArea: Storage | undefined,\n storageKey: string | undefined,\n): string | null {\n if (!storageArea || !storageKey) return null\n const token = getTokenFromStorage(storageArea, storageKey)\n if (token) {\n return token\n }\n return null\n}\n","import {type Subscription} from 'rxjs'\n\nimport {type TokenSource} from '../config/sanityConfig'\nimport {type StoreContext} from '../store/defineStore'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState, type LoggedInAuthState} from './authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from './authStrategy'\nimport {refreshStampedToken} from './refreshStampedToken'\nimport {checkForCookieAuth, getStudioTokenFromLocalStorage} from './studioModeAuth'\nimport {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'\nimport {subscribeToStorageEventsAndSetToken} from './subscribeToStorageEventsAndSetToken'\nimport {createLoggedInAuthState, getDefaultStorage} from './utils'\n\n/**\n * Resolves the initial auth state for Studio mode.\n *\n * When a `tokenSource` is provided (via `config.studio.auth.token`), the\n * initial state is `LOGGING_IN` — the actual token arrives asynchronously\n * via the subscription set up in `initializeStudioAuth`.\n *\n * Fallback token discovery order (no tokenSource):\n * 1. Provided token (`auth.token` in config)\n * 2. localStorage: `__studio_auth_token_${projectId}`\n * 3. Falls back to `LOGGED_OUT` (cookie auth is checked async in `initializeStudioAuth`)\n *\n * @internal\n */\nexport function getStudioInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, projectId, tokenSource} = options\n const storageArea = authConfig.storageArea ?? getDefaultStorage()\n const studioStorageKey = `__studio_auth_token_${projectId ?? ''}`\n\n // When a reactive token source is available, start in LOGGING_IN state.\n // The actual token will arrive via subscription in initializeStudioAuth.\n if (tokenSource) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey: studioStorageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n\n // Fallback: discover token from config or localStorage\n const providedToken = authConfig.token\n\n // Check localStorage first — mirrors original authStore behavior where\n // the localStorage read always runs before the providedToken check.\n let authMethod: AuthStrategyResult['authMethod'] = undefined\n const token = getStudioTokenFromLocalStorage(storageArea, studioStorageKey)\n if (token) {\n authMethod = 'localstorage'\n }\n\n if (providedToken) {\n return {\n authState: createLoggedInAuthState(providedToken, null),\n storageKey: studioStorageKey,\n storageArea,\n authMethod,\n dashboardContext: {},\n }\n }\n\n if (token) {\n return {\n authState: createLoggedInAuthState(token, null),\n storageKey: studioStorageKey,\n storageArea,\n authMethod: 'localstorage',\n dashboardContext: {},\n }\n }\n\n // No token found — start logged out, cookie auth will be checked asynchronously\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey: studioStorageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n}\n\n/**\n * Initialize Studio auth subscriptions.\n *\n * When a `tokenSource` is available (reactive path), subscribes to it for\n * ongoing token sync. The Studio is the token authority — no independent\n * token refresh or cookie auth probing is needed.\n *\n * Fallback path (no tokenSource):\n * - Subscribe to state changes and fetch current user\n * - Subscribe to storage events for studio token key\n * - Check for cookie auth asynchronously if no token was found\n * - Start stamped token refresh\n *\n * @internal\n */\nexport function initializeStudioAuth(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const tokenSource = context.instance.config.studio?.auth?.token\n\n // Reactive token path — Studio provides the token\n if (tokenSource) {\n return initializeWithTokenSource(context, tokenSource)\n }\n\n // Fallback path — discover token from localStorage/cookies\n return initializeWithFallback(context, tokenRefresherRunning)\n}\n\n/**\n * Subscribe to a reactive token source from the Studio workspace.\n *\n * When the token source emits a non-null token, the SDK uses it directly.\n * When it emits `null`, the behavior depends on the `authenticated` flag\n * from the Studio's workspace config:\n *\n * - `authenticated: true` — the Studio has already verified the user is\n * logged in (e.g. via cookie auth). The SDK treats the null token as\n * cookie-based auth and stays in the LOGGED_IN state.\n *\n * - `authenticated` absent/false — the user is genuinely not authenticated;\n * transition to LOGGED_OUT.\n *\n * No async cookie probing is needed here because this code path only runs\n * when a Studio provides SDKStudioContext, and the Studio's Workspace type\n * always includes `authenticated`. The async `checkForCookieAuth` fallback\n * remains in `initializeWithFallback` for the non-Studio path.\n */\nfunction initializeWithTokenSource(\n context: StoreContext<AuthStoreState>,\n tokenSource: TokenSource,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n const studioAuthenticated = context.instance.config.studio?.authenticated === true\n\n // Subscribe to the current user fetcher — runs whenever auth state changes\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: true}))\n\n // Subscribe to the Studio's token stream\n const tokenSub = tokenSource.subscribe({\n next: (token) => {\n const {state} = context\n if (token) {\n // Studio provided a real token — use it directly\n state.set('studioTokenSource', (prev) => ({\n options: {...prev.options, authMethod: undefined},\n authState: createLoggedInAuthState(token, null),\n }))\n } else if (studioAuthenticated) {\n // The Studio says the user is authenticated — null token means\n // cookie-based auth is in use. Stay logged in with cookie method.\n state.set('studioTokenSourceCookieAuth', (prev) => ({\n options: {...prev.options, authMethod: 'cookie'},\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? prev.authState\n : createLoggedInAuthState('', null),\n }))\n } else {\n // No token and Studio doesn't confirm authentication — logged out\n state.set('studioTokenSourceLoggedOut', (prev) => ({\n options: {...prev.options, authMethod: undefined},\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n }))\n }\n },\n })\n\n return {\n dispose: () => {\n tokenSub.unsubscribe()\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n // Studio handles token refresh — do not start the SDK's refresher\n tokenRefresherStarted: false,\n }\n}\n\n/**\n * Fallback initialization when no reactive token source is available.\n * Uses localStorage/cookie discovery (existing behavior).\n */\nfunction initializeWithFallback(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n let startedRefresher = false\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: true}))\n\n const storageArea = context.state.get().options?.storageArea\n if (storageArea) {\n subscriptions.push(subscribeToStorageEventsAndSetToken(context))\n }\n\n // If no token found during getInitialState, try cookie auth asynchronously\n try {\n const {instance, state} = context\n const token: string | null =\n state.get().authState?.type === AuthStateType.LOGGED_IN\n ? (state.get().authState as LoggedInAuthState).token\n : null\n\n if (!token) {\n const projectIdValue = instance.config.projectId\n const clientFactory = state.get().options.clientFactory\n checkForCookieAuth(projectIdValue, clientFactory).then((isCookieAuthEnabled) => {\n if (!isCookieAuthEnabled) return\n state.set('enableCookieAuth', (prev) => ({\n options: {...prev.options, authMethod: 'cookie'},\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? prev.authState\n : createLoggedInAuthState('', null),\n }))\n })\n }\n } catch {\n // best-effort cookie detection\n }\n\n if (!tokenRefresherRunning) {\n startedRefresher = true\n subscriptions.push(refreshStampedToken(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: startedRefresher,\n }\n}\n","import {type ClientConfig, createClient, type SanityClient} from '@sanity/client'\nimport {type CurrentUser} from '@sanity/types'\n\nimport {type AuthConfig, type AuthProvider} from '../config/authConfig'\nimport {bindActionGlobally} from '../store/createActionBinder'\nimport {createStateSourceAction} from '../store/createStateSourceAction'\nimport {defineStore} from '../store/defineStore'\nimport {getStagingApiHost} from '../utils/getStagingApiHost'\nimport {getAuthLogger} from './authLogger'\nimport {resolveAuthMode} from './authMode'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStrategyOptions} from './authStrategy'\nimport {getDashboardInitialState, initializeDashboardAuth} from './dashboardAuth'\nimport {getOauthInitialState, initializeOauthAuth} from './oauth/oauthAuth'\nimport {type OAuthTokens} from './oauth/types'\nimport {getStandaloneInitialState, initializeStandaloneAuth} from './standaloneAuth'\nimport {getStudioInitialState, initializeStudioAuth} from './studioAuth'\nimport {createLoggedInAuthState, getCleanedUrl, getDefaultLocation} from './utils'\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Represents the various states the authentication can be in.\n *\n * @public\n */\nexport type AuthState = LoggedInAuthState | LoggedOutAuthState | LoggingInAuthState | ErrorAuthState\n\n/**\n * Logged-in state from the auth state.\n * @public\n */\nexport type LoggedInAuthState = {\n type: AuthStateType.LOGGED_IN\n token: string\n currentUser: CurrentUser | null\n lastTokenRefresh?: number\n}\n\n/**\n * Logged-out state from the auth state.\n * @public\n */\nexport type LoggedOutAuthState = {type: AuthStateType.LOGGED_OUT; isDestroyingSession: boolean}\n\n/**\n * Logging-in state from the auth state.\n * @public\n */\nexport type LoggingInAuthState = {type: AuthStateType.LOGGING_IN; isExchangingToken: boolean}\n\n/**\n * Error state from the auth state.\n * @public\n */\nexport type ErrorAuthState = {type: AuthStateType.ERROR; error: unknown}\n\n/**\n * Represents the various states the authentication can be in.\n *\n * @public\n */\nexport interface DashboardContext {\n mode?: string\n env?: string\n orgId?: string\n}\n\n/**\n * The method of authentication used.\n * @internal\n */\nexport type AuthMethodOptions = 'localstorage' | 'cookie' | undefined\n\nlet tokenRefresherRunning = false\n\n/**\n * @public\n */\nexport interface AuthStoreState {\n authState: AuthState\n providers?: AuthProvider[]\n options: {\n initialLocationHref: string\n clientFactory: (config: ClientConfig) => SanityClient\n customProviders: AuthConfig['providers']\n storageKey: string\n storageArea: Storage | undefined\n apiHost: string | undefined\n loginUrl: string\n callbackUrl: string | undefined\n providedToken: string | undefined\n authMethod: AuthMethodOptions\n oauth: AuthConfig['oauth']\n }\n dashboardContext?: DashboardContext\n oauthTokens?: OAuthTokens\n}\n\n// ---------------------------------------------------------------------------\n// Store definition — thin orchestrator\n// ---------------------------------------------------------------------------\n\nexport const authStore = defineStore<AuthStoreState>({\n name: 'Auth',\n\n getInitialState(instance) {\n const logger = getAuthLogger(instance)\n\n logger.debug('Initializing auth store', {\n hasProvidedToken: !!instance.config.auth?.token,\n hasCustomProviders: !!(\n instance.config.auth?.providers && instance.config.auth.providers.length > 0\n ),\n })\n\n const {\n apiHost: configApiHost,\n callbackUrl,\n providers: customProviders,\n token: providedToken,\n clientFactory = createClient,\n initialLocationHref = getDefaultLocation(),\n } = instance.config.auth ?? {}\n\n const apiHost = configApiHost ?? getStagingApiHost()\n const authConfig = instance.config.auth ?? {}\n\n // Build login URL (used by standalone mode, but always computed for the\n // public `getLoginUrlState` accessor)\n let loginDomain = 'https://www.sanity.io'\n try {\n if (apiHost && new URL(apiHost).hostname.endsWith('.sanity.work')) {\n loginDomain = 'https://www.sanity.work'\n }\n } catch {\n /* empty */\n }\n const loginUrl = new URL('/login', loginDomain)\n loginUrl.searchParams.set('origin', getCleanedUrl(initialLocationHref))\n loginUrl.searchParams.set('type', 'stampedToken') // Token must be stamped to have an sid passed back\n loginUrl.searchParams.set('withSid', 'true')\n\n // Resolve auth mode and delegate to the appropriate strategy\n const mode = resolveAuthMode(instance.config, initialLocationHref)\n\n const strategyOptions: AuthStrategyOptions = {\n authConfig,\n projectId: instance.config.projectId,\n initialLocationHref,\n clientFactory,\n tokenSource: instance.config.studio?.auth?.token,\n }\n\n let result\n switch (mode) {\n case 'studio':\n result = getStudioInitialState(strategyOptions)\n break\n case 'oauth':\n result = getOauthInitialState(strategyOptions)\n break\n case 'dashboard':\n result = getDashboardInitialState(strategyOptions)\n break\n case 'standalone':\n result = getStandaloneInitialState(strategyOptions)\n break\n }\n\n logger.debug('Auth state initialized', {\n authStateType: result.authState.type,\n mode,\n authMethod: result.authMethod,\n })\n\n return {\n authState: result.authState,\n dashboardContext: result.dashboardContext,\n oauthTokens: result.oauthTokens,\n options: {\n apiHost,\n loginUrl: loginUrl.toString(),\n callbackUrl,\n customProviders,\n providedToken,\n clientFactory,\n initialLocationHref,\n storageKey: result.storageKey,\n storageArea: result.storageArea,\n authMethod: result.authMethod,\n // Only expose oauth options when the oauth strategy is actually in use,\n // so mode-gated actions (logout, handleAuthCallback) stay consistent\n // with the resolved mode (e.g. `studio` takes precedence over `oauth`).\n oauth: mode === 'oauth' ? authConfig.oauth : undefined,\n },\n }\n },\n\n initialize(context) {\n const logger = getAuthLogger(context.instance)\n\n const initialLocationHref =\n context.state.get().options?.initialLocationHref ?? getDefaultLocation()\n const mode = resolveAuthMode(context.instance.config, initialLocationHref)\n\n logger.debug('Setting up auth subscriptions', {mode})\n\n let initResult\n switch (mode) {\n case 'studio':\n initResult = initializeStudioAuth(context, tokenRefresherRunning)\n break\n case 'oauth':\n initResult = initializeOauthAuth(context)\n break\n case 'dashboard':\n initResult = initializeDashboardAuth(context, tokenRefresherRunning)\n break\n case 'standalone':\n initResult = initializeStandaloneAuth(context, tokenRefresherRunning)\n break\n }\n\n if (initResult.tokenRefresherStarted) {\n tokenRefresherRunning = true\n }\n\n return () => {\n logger.debug('Cleaning up auth subscriptions')\n initResult.dispose()\n }\n },\n})\n\n// ---------------------------------------------------------------------------\n// Public bound actions\n// ---------------------------------------------------------------------------\n\n/**\n * @public\n */\nexport const getCurrentUserState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {authState}}) =>\n authState.type === AuthStateType.LOGGED_IN ? authState.currentUser : null,\n ),\n)\n\n/**\n * @public\n */\nexport const getTokenState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {authState}}) =>\n authState.type === AuthStateType.LOGGED_IN ? authState.token : null,\n ),\n)\n\n/**\n * @internal\n */\nexport const getAuthMethodState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {options}}) => options.authMethod),\n)\n\n/**\n * @public\n */\nexport const getLoginUrlState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {options}}) => options.loginUrl),\n)\n\n/**\n * @public\n */\nexport const getAuthState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {authState}}) => authState),\n)\n\n/**\n * Returns a state source indicating if the SDK is running within a dashboard context.\n * @public\n */\nexport const getIsInDashboardState = bindActionGlobally(\n authStore,\n createStateSourceAction(\n ({state: {dashboardContext}}) =>\n // Check if dashboardContext exists and is not empty\n !!dashboardContext && Object.keys(dashboardContext).length > 0,\n ),\n)\n\n/**\n * Action to explicitly set the authentication token.\n * Used internally by the Comlink token refresh.\n * @internal\n */\nexport const setAuthToken = bindActionGlobally(\n authStore,\n ({state, instance}, token: string | null) => {\n const logger = getAuthLogger(instance)\n\n const currentAuthState = state.get().authState\n if (token) {\n // Update state only if the new token is different or currently logged out\n if (currentAuthState.type !== AuthStateType.LOGGED_IN || currentAuthState.token !== token) {\n logger.info('Setting auth token')\n const currentUser =\n currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.currentUser : null\n const preservedLastTokenRefresh =\n currentAuthState.type === AuthStateType.LOGGED_IN\n ? currentAuthState.lastTokenRefresh\n : undefined\n state.set('setToken', {\n authState: createLoggedInAuthState(token, currentUser, preservedLastTokenRefresh),\n })\n }\n } else {\n // Handle setting token to null (logging out)\n if (currentAuthState.type !== AuthStateType.LOGGED_OUT) {\n logger.info('Clearing auth token')\n state.set('setToken', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n })\n }\n }\n },\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"authStore-DwKgZOzo.js","names":["createClient","\"DEBUG\"","\"NODE_ENV\"","\"internal\"","\"LOGGED_IN\"","\"LOGGING_IN\"","\"ERROR\"","\"LOGGED_OUT\""],"sources":["../src/utils/logger.ts","../src/utils/getStagingApiHost.ts","../src/auth/authLogger.ts","../src/dashboard/messageBus/topics.ts","../src/dashboard/messageBus/bus.ts","../src/auth/authConstants.ts","../src/auth/authMode.ts","../src/auth/authStateType.ts","../src/auth/refreshStampedToken.ts","../src/auth/subscribeToStateAndFetchCurrentUser.ts","../src/auth/utils.ts","../src/auth/dashboardAuth.ts","../src/auth/oauth/oauthClient.ts","../src/auth/oauth/oauthRefresh.ts","../src/auth/oauth/oauthAuth.ts","../src/auth/subscribeToStorageEventsAndSetToken.ts","../src/auth/standaloneAuth.ts","../src/auth/studioModeAuth.ts","../src/auth/studioAuth.ts","../src/auth/authStore.ts"],"sourcesContent":["/**\n * Logging infrastructure for the Sanity SDK\n *\n * Provides multi-level, namespace-based logging for both SDK users and maintainers.\n * In production builds, all logging can be stripped via tree-shaking.\n *\n * @example SDK User\n * ```ts\n * import {configureLogging} from '@sanity/sdk'\n *\n * configureLogging({\n * level: 'info',\n * namespaces: ['auth', 'document']\n * })\n * ```\n *\n * @example SDK Maintainer\n * ```ts\n * configureLogging({\n * level: 'trace',\n * namespaces: ['*'],\n * internal: true\n * })\n * ```\n */\n\n/**\n * Log levels in order of verbosity (least to most)\n * - error: Critical failures that prevent operation\n * - warn: Issues that may cause problems but don't stop execution\n * - info: High-level informational messages (SDK user level)\n * - debug: Detailed debugging information (maintainer level)\n * - trace: Very detailed tracing (maintainer level, includes RxJS streams)\n * @public\n */\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace'\n\n/**\n * Log namespaces organize logs by functional domain\n *\n * @remarks\n * This is an extensible string type. As logging is added to more modules,\n * additional namespaces will be recognized. Currently implemented namespaces\n * will be documented as they are added.\n * @internal\n */\nexport type LogNamespace = string\n\n/**\n * Configuration for the logging system\n * @public\n */\nexport interface LoggerConfig {\n /**\n * Minimum log level to output\n * @defaultValue 'warn'\n */\n level?: LogLevel\n\n /**\n * Namespaces to enable. Use ['*'] for all namespaces\n * @defaultValue []\n * @remarks\n * Available namespaces depend on which modules have logging integrated.\n * Check the SDK documentation for the current list of instrumented modules.\n * @example ['auth', 'document']\n */\n namespaces?: string[]\n\n /**\n * Enable internal/maintainer-level logging\n * Shows RxJS streams, store internals, etc.\n * @defaultValue false\n */\n internal?: boolean\n\n /**\n * Custom log handler (for testing or custom output)\n * @defaultValue console methods\n */\n handler?: LogHandler\n\n /**\n * Enable timestamps in log output\n * @defaultValue true\n */\n timestamps?: boolean\n\n /**\n * Enable in production builds\n * @defaultValue false\n */\n enableInProduction?: boolean\n}\n\n/**\n * Custom log handler interface\n *\n * @internal\n */\nexport interface LogHandler {\n error: (message: string, context?: LogContext) => void\n warn: (message: string, context?: LogContext) => void\n info: (message: string, context?: LogContext) => void\n debug: (message: string, context?: LogContext) => void\n trace: (message: string, context?: LogContext) => void\n}\n\n/**\n * Context object attached to log messages\n *\n * This interface allows you to attach arbitrary contextual data to log messages.\n * The index signature `[key: string]: unknown` enables you to add any custom\n * properties relevant to your log entry (e.g., `userId`, `documentId`, `action`, etc.).\n *\n * **Sensitive data sanitization:**\n * Top-level keys containing sensitive names (`token`, `password`, `secret`, `apiKey`,\n * `authorization`) are automatically redacted to `[REDACTED]` in log output.\n *\n * @example\n * ```ts\n * logger.info('User logged in', {\n * userId: '123', // Custom context\n * action: 'login', // Custom context\n * token: 'secret' // Will be redacted to [REDACTED]\n * })\n * ```\n *\n * @internal\n */\nexport interface LogContext {\n /**\n * Custom context properties that provide additional information about the log entry.\n * Any key-value pairs can be added here (e.g., userId, documentId, requestId, etc.).\n * Keys with sensitive names (token, password, secret, apiKey, authorization) are\n * automatically sanitized.\n */\n [key: string]: unknown\n /** Error object if logging an error */\n error?: Error | unknown\n /** Duration in milliseconds for timed operations */\n duration?: number\n /** Stack trace for debugging */\n stack?: string\n /** Instance context (automatically added when available) */\n instanceContext?: InstanceContext\n}\n\n/**\n * Instance context information automatically added to logs\n * @internal\n */\nexport interface InstanceContext {\n /** Unique instance ID */\n instanceId?: string\n /** Project ID */\n projectId?: string\n /** Dataset name */\n dataset?: string\n}\n\n/**\n * Logger instance for a specific namespace\n * @internal\n */\nexport interface Logger {\n readonly namespace: string\n error: (message: string, context?: LogContext) => void\n warn: (message: string, context?: LogContext) => void\n info: (message: string, context?: LogContext) => void\n debug: (message: string, context?: LogContext) => void\n trace: (message: string, context?: LogContext) => void\n /** Check if a log level is enabled (for performance-sensitive code) */\n isLevelEnabled: (level: LogLevel) => boolean\n /** Create a child logger with extended context */\n child: (context: LogContext) => Logger\n /** Get the instance context if available */\n getInstanceContext: () => InstanceContext | undefined\n}\n\n// Log level priority (lower number = higher priority)\nconst LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n}\n\n// Default logging configuration\nconst DEFAULT_CONFIG: Required<LoggerConfig> = {\n level: 'warn',\n namespaces: [],\n internal: false,\n timestamps: true,\n enableInProduction: false,\n handler: {\n // eslint-disable-next-line no-console\n error: console.error.bind(console),\n // eslint-disable-next-line no-console\n warn: console.warn.bind(console),\n // eslint-disable-next-line no-console\n info: console.info.bind(console),\n // eslint-disable-next-line no-console\n debug: console.debug.bind(console),\n // eslint-disable-next-line no-console\n trace: console.debug.bind(console), // trace uses console.debug\n },\n}\n\n/**\n * Parse DEBUG environment variable for automatic logging configuration\n *\n * Supports patterns similar to Sanity CLI/Studio:\n * - DEBUG=sanity:* (all namespaces, debug level)\n * - DEBUG=sanity:auth,sanity:document (specific namespaces)\n * - DEBUG=sanity:trace:* (all namespaces, trace level)\n * - DEBUG=sanity:*:internal (enable internal logs)\n *\n * @internal\n */\nexport function parseDebugEnvVar(): Partial<LoggerConfig> | null {\n if (typeof process === 'undefined' || !process.env?.['DEBUG']) {\n return null\n }\n\n const debug = process.env['DEBUG']\n\n // Only process if it includes 'sanity'\n if (!debug.includes('sanity')) {\n return null\n }\n\n const config: Partial<LoggerConfig> = {}\n\n // Parse level from pattern like \"sanity:trace:*\" or \"sanity:debug:*\"\n const levelMatch = debug.match(/sanity:(trace|debug|info|warn|error):/)\n const hasLevelSpecifier = !!levelMatch\n if (levelMatch) {\n config.level = levelMatch[1] as LogLevel\n } else {\n // Default to debug level if just \"sanity:*\" or \"sanity:namespace\"\n config.level = 'debug'\n }\n\n // Parse namespaces\n if (debug === 'sanity') {\n config.namespaces = ['*']\n } else if (hasLevelSpecifier && debug.match(/sanity:(trace|debug|info|warn|error):\\*/)) {\n // Pattern like \"sanity:trace:*\" - wildcard after level\n config.namespaces = ['*']\n } else if (!hasLevelSpecifier && debug.includes('sanity:*')) {\n // Pattern like \"sanity:*\" - wildcard without level\n config.namespaces = ['*']\n } else {\n // Extract specific namespaces like \"sanity:auth,sanity:document\"\n const namespaces = debug\n .split(',')\n .filter((s) => s.includes('sanity:'))\n .map((s) => {\n // Remove 'sanity:' prefix\n const cleaned = s.replace(/^sanity:/, '')\n // If there's a level specifier, skip it\n if (hasLevelSpecifier && cleaned.match(/^(trace|debug|info|warn|error):/)) {\n // Get the part after the level: \"trace:auth\" -> \"auth\"\n return cleaned.split(':').slice(1).join(':')\n }\n // Otherwise get the first part: \"auth:something\" -> \"auth\"\n return cleaned.split(':')[0]\n })\n .filter(Boolean)\n .filter((ns) => ns !== '*') // Filter out wildcards\n\n if (namespaces.length > 0) {\n config.namespaces = namespaces\n }\n }\n\n // Check for internal flag: DEBUG=sanity:*:internal\n if (debug.includes(':internal')) {\n config.internal = true\n }\n\n return config\n}\n\n// Global configuration - initialized with env var settings if present\nconst envConfig = parseDebugEnvVar()\nlet globalConfig: Required<LoggerConfig> = {\n ...DEFAULT_CONFIG,\n ...(envConfig ?? {}),\n}\n\n// Log that env var configuration was detected (only if DEBUG is set)\n// Note: This runs at module initialization, difficult to test without complex module mocking\n/* c8 ignore next 14 */\nif (envConfig) {\n const shouldLog =\n ['info', 'debug', 'trace'].includes(globalConfig.level) || globalConfig.level === 'warn'\n if (shouldLog) {\n // eslint-disable-next-line no-console\n console.info(\n `[${new Date().toISOString()}] [INFO] [sdk] Logging auto-configured from DEBUG environment variable`,\n {\n level: globalConfig.level,\n namespaces: globalConfig.namespaces,\n internal: globalConfig.internal,\n source: 'env:DEBUG',\n value: typeof process !== 'undefined' ? process.env?.['DEBUG'] : undefined,\n },\n )\n }\n}\n\n/**\n * Configure the global logging system\n * @public\n */\nexport function configureLogging(config: LoggerConfig): void {\n globalConfig = {\n ...globalConfig,\n ...config,\n handler: config.handler ?? globalConfig.handler,\n }\n}\n\n/**\n * Get the current logging configuration\n * @internal\n */\nexport function getLoggingConfig(): Readonly<Required<LoggerConfig>> {\n return globalConfig\n}\n\n/**\n * Reset logging to default configuration\n * @internal\n */\nexport function resetLogging(): void {\n globalConfig = {...DEFAULT_CONFIG}\n}\n\n/**\n * Check if logging is enabled in the current environment\n * @internal\n */\nfunction isLoggingEnabled(): boolean {\n // In production, only log if explicitly enabled\n if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] === 'production') {\n return globalConfig.enableInProduction\n }\n return true\n}\n\n/**\n * Check if a namespace is enabled\n * @internal\n */\nfunction isNamespaceEnabled(namespace: string): boolean {\n if (!isLoggingEnabled()) return false\n if (globalConfig.namespaces.includes('*')) return true\n return globalConfig.namespaces.includes(namespace)\n}\n\n/**\n * Check if a log level is enabled\n * @internal\n */\nfunction isLevelEnabled(level: LogLevel): boolean {\n if (!isLoggingEnabled()) return false\n return LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[globalConfig.level]\n}\n\n/**\n * Format a log message with timestamp, namespace, and instance context\n * @internal\n */\nfunction formatMessage(\n namespace: LogNamespace,\n level: LogLevel,\n message: string,\n context?: LogContext,\n): [string, LogContext | undefined] {\n const parts: string[] = []\n\n if (globalConfig.timestamps) {\n const timestamp = new Date().toISOString()\n parts.push(`[${timestamp}]`)\n }\n\n parts.push(`[${level.toUpperCase()}]`)\n parts.push(`[${namespace}]`)\n\n // Add instance context if available\n const instanceContext = context?.instanceContext\n if (instanceContext) {\n if (instanceContext.projectId) {\n parts.push(`[project:${instanceContext.projectId}]`)\n }\n if (instanceContext.dataset) {\n parts.push(`[dataset:${instanceContext.dataset}]`)\n }\n if (instanceContext.instanceId) {\n parts.push(`[instance:${instanceContext.instanceId.slice(0, 8)}]`)\n }\n }\n\n parts.push(message)\n\n return [parts.join(' '), context]\n}\n\n/**\n * Sanitize context for logging (remove sensitive data)\n * @internal\n * @remarks\n * This performs shallow sanitization only - it redacts top-level keys that contain\n * sensitive names (token, password, secret, apiKey, authorization).\n * Nested sensitive data (e.g., `\\{auth: \\{token: 'secret'\\}\\}`) will NOT be redacted.\n * If deep sanitization is needed in the future, this can be enhanced to recursively\n * traverse nested objects.\n */\nfunction sanitizeContext(context?: LogContext): LogContext | undefined {\n if (!context || Object.keys(context).length === 0) return undefined\n\n const sanitized = {...context}\n\n // Remove or redact sensitive fields at the top level\n const sensitiveKeys = ['token', 'password', 'secret', 'apiKey', 'authorization']\n for (const key of Object.keys(sanitized)) {\n if (sensitiveKeys.some((sensitive) => key.toLowerCase().includes(sensitive))) {\n sanitized[key] = '[REDACTED]'\n }\n }\n\n return sanitized\n}\n\n/**\n * Create a logger for a specific namespace\n * @param namespace - A string identifier for the logging domain (e.g., 'auth', 'document')\n * @param baseContext - Optional base context to include in all log messages\n * @remarks\n * If baseContext includes an `instanceContext` property (with projectId, dataset, instanceId),\n * it will be automatically formatted into the log output for easier debugging of\n * multi-instance scenarios.\n * @public\n */\nexport function createLogger(namespace: string, baseContext?: LogContext): Logger {\n const logAtLevel = (level: LogLevel, message: string, context?: LogContext) => {\n // Early return if namespace or level not enabled\n if (!isNamespaceEnabled(namespace)) return\n if (!isLevelEnabled(level)) return\n\n // Skip internal logs if not enabled\n if (context?.['internal'] && !globalConfig.internal) return\n\n const mergedContext = {...baseContext, ...context}\n const sanitized = sanitizeContext(mergedContext)\n const [formatted, finalContext] = formatMessage(namespace, level, message, sanitized)\n\n globalConfig.handler[level](formatted, finalContext)\n }\n\n const logger: Logger = {\n namespace,\n error: (message, context) => logAtLevel('error', message, context),\n warn: (message, context) => logAtLevel('warn', message, context),\n info: (message, context) => logAtLevel('info', message, context),\n debug: (message, context) => logAtLevel('debug', message, context),\n trace: (message, context) => logAtLevel('trace', message, {...context, internal: true}),\n isLevelEnabled: (level) => isNamespaceEnabled(namespace) && isLevelEnabled(level),\n child: (childContext) => createLogger(namespace, {...baseContext, ...childContext}),\n getInstanceContext: () => baseContext?.instanceContext,\n }\n\n return logger\n}\n\n/**\n * Create a performance timer for measuring operation duration\n * @internal\n */\nexport function createTimer(\n namespace: string,\n operation: string,\n): {end: (message?: string, context?: LogContext) => number} {\n const logger = createLogger(namespace)\n const start = performance.now()\n\n return {\n end: (message?: string, context?: LogContext): number => {\n const duration = performance.now() - start\n logger.debug(message ?? `${operation} completed`, {\n ...context,\n operation,\n duration,\n })\n return duration\n },\n }\n}\n\n/**\n * Utility to log RxJS operator execution (for maintainers)\n * Will be exported in future PR when logging is added to stores\n * @internal\n */\n/* c8 ignore next 4 */\nfunction logRxJSOperator(namespace: string, operator: string, context?: LogContext): void {\n const logger = createLogger(namespace)\n logger.trace(`RxJS: ${operator}`, {...context, internal: true, operator})\n}\n\n/**\n * Extract instance context from a SanityInstance for logging\n * Will be exported in future PR when logging is added to stores\n * @param instance - The SanityInstance to extract context from\n * @returns Instance context suitable for logging\n * @internal\n */\n/* c8 ignore next 7 */\nfunction getInstanceContext(instance: {\n instanceId?: string\n config?: {projectId?: string; dataset?: string}\n}): InstanceContext {\n return {\n instanceId: instance.instanceId,\n projectId: instance.config?.projectId,\n dataset: instance.config?.dataset,\n }\n}\n\n// Prevent unused function warnings - these will be exported and used in future PRs\n/* c8 ignore next 2 */\nvoid logRxJSOperator\nvoid getInstanceContext\n","declare const __SANITY_STAGING__: boolean | undefined\n\n/**\n * Returns the staging API host if the `__SANITY_STAGING__` build-time flag is\n * set to `true` (mirroring how Sanity Studio detects staging builds).\n *\n * @internal\n */\nexport function getStagingApiHost(): string | undefined {\n if (typeof __SANITY_STAGING__ !== 'undefined' && __SANITY_STAGING__ === true) {\n return 'https://api.sanity.work'\n }\n return undefined\n}\n","import {type SanityInstance} from '../store/createSanityInstance'\nimport {createLogger, type Logger} from '../utils/logger'\n\nconst loggers = new WeakMap<SanityInstance, Logger>()\n\n/**\n * Returns the auth logger for a Sanity instance, creating it on first use.\n *\n * The logger is cached per instance so repeated action calls (logout,\n * setAuthToken, handleAuthCallback) reuse the same logger instead of\n * rebuilding it. The instance details are nested under `instanceContext`,\n * which is what the logger's formatter reads to render the\n * `[project:x] [dataset:y] [instance:z]` prefix.\n *\n * @internal\n */\nexport function getAuthLogger(instance: SanityInstance): Logger {\n let logger = loggers.get(instance)\n if (!logger) {\n logger = createLogger('auth', {\n instanceContext: {\n instanceId: instance.instanceId,\n projectId: instance.config.projectId,\n dataset: instance.config.dataset,\n },\n })\n loggers.set(instance, logger)\n }\n return logger\n}\n","import {type CurrentUser} from '@sanity/types'\n\nimport {type AccessResourceType} from '../../access/checkPermissions'\nimport {type Application, type ApplicationInclude} from '../../applications/applications'\nimport {type Installation, type InstallationInclude} from '../../installations/installations'\nimport {type OrganizationBase} from '../../organization/organization'\n\n/**\n * Identifies a module federation expose and the manifest that serves it.\n * @public\n * @category Remote Modules\n */\nexport interface RemoteModuleRef {\n readonly entry: string\n readonly moduleId: string\n readonly version: string\n}\n\n/**\n * Application types that can receive configuration modules.\n *\n * The dashboard supplies this value over the message bus, so any string is accepted; known\n * types are listed for autocomplete. `& {}` keeps the literal from collapsing into `string`.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type ApplicationConfigAppType = 'media-library' | (string & {})\n\n/**\n * Identifies a configuration module for an application or application type.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport interface ApplicationConfig extends RemoteModuleRef {\n readonly appId?: Application['id']\n readonly appType: ApplicationConfigAppType\n}\n\n/**\n * The capabilities a host can provide.\n *\n * Reuses the Studio's rendering-context identifiers so an application can hide its own\n * implementation of anything the host provides.\n * @public\n * @category Message Bus\n */\nexport const capabilities = ['globalUserMenu', 'favorites', 'history'] as const\n\n/**\n * A capability a host can provide.\n * @public\n * @category Message Bus\n */\nexport type Capability = (typeof capabilities)[number]\n\n/**\n * The capabilities the host provides. A missing key means the host does not provide it.\n * @public\n * @category Message Bus\n */\nexport type CapabilityRecord = Partial<Record<Capability, boolean>>\n\n/**\n * A document a user viewed, edited, created, or deleted in an application.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport interface DocumentActivity {\n readonly kind: 'document'\n readonly eventType: 'viewed' | 'edited' | 'created' | 'deleted'\n readonly document: {\n readonly id: string\n readonly type: string\n readonly resource: {\n readonly id: string\n readonly type: 'dataset' | 'media-library' | 'canvas'\n /** Schema collection the document belongs to; the workspace name for studios. */\n readonly schemaName?: string\n }\n }\n}\n\n/**\n * Activity an application reports to the host. Discriminated on `kind`.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type ApplicationActivity = DocumentActivity\n\n/**\n * A document a user favorited, addressed like {@link DocumentActivity}'s document.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type FavoriteDocument = DocumentActivity['document']\n\n/**\n * A label rendered for an application interface; `null` clears it.\n * @internal\n */\nexport type ApplicationStatus = {label: string | null}\n\n/**\n * Updates the status rendered for an application interface.\n * @internal\n */\nexport type ApplicationStatusUpdate = {\n /** The application interface name. */\n name: string\n /** The status to render. */\n value: ApplicationStatus\n}\n\n/**\n * What an application is currently showing: the Comlink agent resource context, made generic.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport interface ApplicationContext {\n /** The resource the application is working in. Types follow `@sanity/client`'s resource config. */\n readonly resource: {\n readonly id: string\n readonly type: 'dataset' | 'media-library' | 'canvas'\n }\n /** The open document, or `null` when none is open. */\n readonly document: {readonly id: string} | null\n}\n\n/**\n * An application served by a CLI dev server. The workbench publishes it in the same shape as a\n * deployed application; `local` marks it and names the dev server it is served from.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type LocalApplication = Application<ApplicationInclude> & {\n readonly local: {readonly host: string; readonly port: number}\n}\n\n/**\n * Declares a topic that stores and replays its current value.\n * @public\n * @category Message Bus\n */\nexport type StateTopicDef<T> = {kind: 'state'; value: T}\n\n/**\n * Declares a topic that delivers events and an optional reply.\n * @public\n * @category Message Bus\n */\nexport type EventTopicDef<P, R = never> = {\n kind: 'event'\n payload: P\n reply?: R\n}\n\n/**\n * Represents a successful topic value or a failed topic operation.\n * @public\n * @category Message Bus\n */\nexport type TopicResult<T> = {ok: true; value: T} | {ok: false}\n\n/**\n * Identifies a dashboard application and a route within it.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type NavigationTarget = {\n /** The application ID, or `null` for dashboard-level routes. */\n appId: Application['id'] | null\n /** The route path, including its query string and fragment. */\n path: string\n}\n\n/**\n * Describes the current dashboard location and an active navigation.\n * @public\n * @category Types\n * @category Message Bus\n */\nexport type NavigationLocation = NavigationTarget & {\n /** The active navigation, or `null` when navigation is idle. */\n transition: {\n /** Whether the navigation pushes or replaces browser history. */\n navigationType: 'push' | 'replace'\n /** The requested destination. */\n to: NavigationTarget\n } | null\n}\n\n/**\n * Declares the topics provided by the dashboard.\n * @public\n * @category Message Bus\n */\nexport interface DashboardTopics {\n /**\n * Asks the dashboard to show its access request prompt for a resource the user can't access,\n * scoped like the Access API's `/access/{resourceType}/{resourceId}/requests`. Replies once the\n * prompt is shown. The prompt handles the Access API outcome (SSO enforcement, pending or\n * declined requests, request limits), so the reply doesn't report it.\n *\n * `ok: false` reasons:\n * - `unsupported`: the dashboard doesn't show access requests for the sending application\n * - `already-has-access`: the user already has access to the resource, so there is nothing to request\n */\n 'access.request': EventTopicDef<\n {resourceType: Extract<AccessResourceType, 'organization' | 'project'>; resourceId: string},\n {ok: true} | {ok: false; reason: 'unsupported' | 'already-has-access'}\n >\n /** Reports user activity in an application, e.g. for the recents feed. Fire-and-forget. */\n 'applications.activity': EventTopicDef<ApplicationActivity>\n /**\n * The base path for an application.\n *\n * An unknown application returns `{ok: false}`.\n */\n 'applications.base-path': StateTopicDef<TopicResult<string>>\n /** The capabilities the host provides. A missing key means the host does not provide it. */\n 'applications.capabilities': StateTopicDef<CapabilityRecord>\n /** The available application configuration modules. */\n 'applications.config': StateTopicDef<ApplicationConfig[] | null>\n /** The foreground application's context, or `null` when it has published none. */\n 'applications.context': StateTopicDef<\n (ApplicationContext & {readonly appId: Application['id']}) | null\n >\n /** Publishes the sending application's context. `null` clears it. Fire-and-forget. */\n 'applications.context.update': EventTopicDef<ApplicationContext | null>\n /** The foreground application ID, or `null` on dashboard-level routes. */\n 'applications.foreground': StateTopicDef<Application['id'] | null>\n /**\n * The dashboard applications and installations available to the current user. Each member\n * publishes its own raw serialised record, so the kinds are distinguished by shape: an\n * {@link Application} has a `type` of `'studio' | 'coreApp'`, a {@link LocalApplication} adds\n * `local`, and an {@link Installation} has no `type` and carries `applicationId` with a nested\n * `application` object.\n */\n 'applications.list': StateTopicDef<TopicResult<\n (Application<ApplicationInclude> | LocalApplication | Installation<InstallationInclude>)[]\n > | null>\n 'applications.status.update': EventTopicDef<ApplicationStatusUpdate>\n /**\n * The session token for the reading connection, or `null` while signed out. The host\n * writes it to each connection separately, so one application never sees another's token.\n */\n 'auth.token': StateTopicDef<string | null>\n /** Requests a dashboard session token. */\n 'auth.token.refresh': EventTopicDef<void, string>\n /** The signed-in user's favorited documents, published while the host provides `favorites`. */\n 'favorites.documents': StateTopicDef<FavoriteDocument[]>\n /**\n * Favorites or unfavorites a document. The host replies once `favorites.documents` reflects\n * the change, so a read after the reply sees it. A favorite is identified by its published\n * document ID, type, resource and `schemaName` (workspace).\n */\n 'favorites.update': EventTopicDef<{document: FavoriteDocument; favorited: boolean}, void>\n /** The current dashboard location and active navigation. */\n 'navigation.location': StateTopicDef<NavigationLocation | null>\n /**\n * Requests navigation and replies when the location commits.\n *\n * `ok: false` reasons:\n * - `not-navigable`: the URL cannot be handled by a dashboard application\n * - `interrupted`: another navigation superseded the request\n * - `failed`: the router rejected or did not commit the request\n */\n 'navigation.location.update': EventTopicDef<\n {\n url: string\n history?: 'push' | 'replace'\n },\n {ok: true} | {ok: false; reason: 'not-navigable' | 'interrupted' | 'failed'}\n >\n /** The current organization, or `null` without an active organization. */\n 'organizations.current': StateTopicDef<Pick<OrganizationBase, 'id' | 'name' | 'slug'> | null>\n /** The open panel, its application, display mode, and optional width in pixels. */\n 'panels.mode': StateTopicDef<TopicResult<\n | {appId: string; name: string; mode: 'aside'; size?: number}\n | {appId: string; name: string; mode: 'full'}\n | null\n > | null>\n /** Opens, updates, resizes, or closes an application's panel. */\n 'panels.mode.set': EventTopicDef<\n {name: string; mode: 'aside' | 'full'} | {name: string; size: number} | null\n >\n /** The resolved dashboard color scheme. */\n 'preferences.color-scheme': StateTopicDef<'light' | 'dark'>\n /** Whether the dashboard dock is pinned open. */\n 'preferences.dock-locked': StateTopicDef<boolean>\n /** The signed-in user, or `null` while signed out. */\n 'users.current': StateTopicDef<CurrentUser | null>\n}\n\n/**\n * Declares every topic available through the message bus.\n * @public\n * @category Message Bus\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- Declaration merging extends the SDK manifest.\nexport interface Topics extends DashboardTopics {}\n\n/**\n * Hides provisional topics from the public message bus methods.\n * @internal\n */\nexport type MessageBusTopics = Omit<Topics, 'applications.status.update'>\n\n/**\n * Every declared topic name.\n * @public\n * @category Message Bus\n */\nexport type TopicName<TTopics = Topics> = keyof TTopics\n\ntype StateTopicsOf<T> = {\n [K in keyof T]: T[K] extends {kind: 'state'} ? K : never\n}[keyof T]\n\n/**\n * Names of state topics exposed by message bus methods.\n * @public\n * @category Message Bus\n */\nexport type StateTopic<TTopics = MessageBusTopics> = StateTopicsOf<TTopics>\n\ntype TopicOwnership = {readonly type: 'same_app'} | {readonly type: 'any_app'}\n\n// State is only ever written by the host, one connection at a time, so it carries no ownership.\ntype TopicManifestEntry<T> = T extends {kind: 'state'; value: infer V}\n ? {readonly kind: 'state'; readonly seed: V | undefined}\n : {readonly kind: 'event'; readonly ownership: TopicOwnership}\n\n// The value a connection's copy of the topic starts with; `undefined` means unpublished.\nconst stateTopic = <const V>(seed: V) => ({kind: 'state', seed}) as const\n\n// `same_app` restricts responding to the application that installed the bus.\nconst dashboardEvent = {kind: 'event', ownership: {type: 'same_app'}} as const\n\ntype DashboardTopicManifest = {\n readonly [K in keyof DashboardTopics]: TopicManifestEntry<DashboardTopics[K]>\n}\n\n/**\n * Defines the runtime kind, ownership, and initial value of dashboard topics.\n * @internal\n */\nexport const DASHBOARD_TOPIC_MANIFEST: DashboardTopicManifest = {\n 'access.request': dashboardEvent,\n 'applications.activity': dashboardEvent,\n 'applications.base-path': stateTopic(undefined),\n 'applications.capabilities': stateTopic(undefined),\n 'applications.config': stateTopic(undefined),\n 'applications.context': stateTopic(undefined),\n 'applications.context.update': dashboardEvent,\n 'applications.foreground': stateTopic(undefined),\n 'applications.list': stateTopic(undefined),\n 'applications.status.update': dashboardEvent,\n 'auth.token': stateTopic(undefined),\n 'auth.token.refresh': dashboardEvent,\n 'favorites.documents': stateTopic(undefined),\n 'favorites.update': dashboardEvent,\n 'navigation.location': stateTopic(undefined),\n 'navigation.location.update': dashboardEvent,\n 'organizations.current': stateTopic(undefined),\n 'panels.mode': stateTopic({ok: true, value: null}),\n 'panels.mode.set': dashboardEvent,\n 'preferences.color-scheme': stateTopic(undefined),\n 'preferences.dock-locked': stateTopic(undefined),\n 'users.current': stateTopic(undefined),\n}\n\n/**\n * Defines the runtime manifest accepted from any message bus version.\n * @internal\n */\nexport type TopicManifest = Readonly<\n Record<\n string,\n | {readonly kind: 'state'; readonly seed: unknown}\n | {readonly kind: 'event'; readonly ownership: TopicOwnership}\n >\n>\n\n/**\n * Names of event topics exposed by message bus methods.\n * @public\n * @category Message Bus\n */\nexport type EventTopic<TTopics = MessageBusTopics> = {\n [K in keyof TTopics]: TTopics[K] extends {kind: 'event'} ? K : never\n}[keyof TTopics]\n\n/**\n * The value type of a state topic.\n * @public\n * @category Message Bus\n */\nexport type ValueOf<K extends StateTopic<TTopics>, TTopics = Topics> =\n TTopics[K] extends StateTopicDef<infer T> ? T : never\n\n/**\n * The payload type of an event topic.\n * @public\n * @category Message Bus\n */\nexport type PayloadOf<K extends EventTopic<TTopics>, TTopics = Topics> =\n TTopics[K] extends EventTopicDef<infer P, infer _R> ? P : never\n\n/**\n * The reply type of an event topic (`never` if it declares none).\n * @public\n * @category Message Bus\n */\nexport type ReplyOf<K extends EventTopic<TTopics>, TTopics = Topics> =\n TTopics[K] extends EventTopicDef<infer _P, infer R> ? R : never\n\n/**\n * Converts a topic value between 2 adjacent versions.\n * @internal\n */\nexport interface TopicMigration {\n /** The older version. */\n readonly from: number\n /** The newer version. */\n readonly to: number\n /** Converts an older state value or event payload to the newer version. */\n up(older: unknown): unknown\n /** Converts a newer state value or event payload to the older version. */\n down(newer: unknown): unknown\n /** Converts event replies between these versions. */\n readonly reply?: {\n /** Converts an older reply to the newer version. */\n up(older: unknown): unknown\n /** Converts a newer reply to the older version. */\n down(newer: unknown): unknown\n }\n}\n\n/**\n * Defines the bundled migration chain for each topic.\n * @internal\n */\nexport const topicMigrations: Partial<Record<TopicName, readonly TopicMigration[]>> = {}\n","/* eslint-disable no-console -- The bus can initialize before the SDK logger exists. */\nimport {\n BehaviorSubject,\n concat,\n defer,\n filter,\n firstValueFrom,\n from,\n map,\n type Observable,\n ReplaySubject,\n Subject,\n type Subscription,\n takeUntil,\n} from 'rxjs'\n\nimport {type Application} from '../../applications/applications'\nimport {\n DASHBOARD_TOPIC_MANIFEST,\n type EventTopic,\n type MessageBusTopics,\n type PayloadOf,\n type ReplyOf,\n type StateTopic,\n type TopicManifest,\n type TopicMigration,\n topicMigrations,\n type TopicName,\n type Topics,\n type ValueOf,\n} from './topics'\n\n/**\n * A message bus protocol error code.\n * @public\n * @category Message Bus\n */\nexport type MessageBusErrorCode =\n | 'NO_RESPONDER'\n | 'TIMEOUT'\n | 'ABORTED'\n | 'HANDLER_THREW'\n | 'PROTOCOL_MISMATCH'\n | 'OWNERSHIP_MISMATCH'\n | 'MISSING_APP_ID'\n | 'REFUSED'\n\n/**\n * An error raised by the message bus protocol.\n * @public\n * @category Message Bus\n */\nexport class MessageBusError extends Error {\n /** The machine-readable protocol error code. */\n readonly code: MessageBusErrorCode\n\n /** Creates a message bus protocol error. */\n constructor(code: MessageBusErrorCode, message?: string, options?: {cause?: unknown}) {\n super(message ?? code, options)\n this.name = 'MessageBusError'\n this.code = code\n }\n}\n\n/**\n * Metadata that travels with each message bus event.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusMeta {\n /** The application that produced the message. */\n appId: Application['id']\n /**\n * The federation module id of the connection that sent the message (e.g.\n * `favorites/views/list/panel`). Absent from older copies and when the host\n * supplied none, so readers normalise with `message.meta.moduleId ?? message.meta.appId`.\n */\n moduleId?: string\n /** The Unix timestamp in milliseconds when the message was produced. */\n timestamp: number\n}\n\n/**\n * A message delivered to an event topic responder.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusMessage<T, R = never, K extends PropertyKey = TopicName> {\n /** The topic that carries the message. */\n type: K\n /** The event payload. */\n payload: T\n /** The message provenance. */\n meta: MessageBusMeta\n /** Replies to an awaiting sender. */\n reply(value: R): void\n /**\n * Refuses the message: the sender's awaited `emit()` rejects with a\n * {@link MessageBusError} whose `code` is `'REFUSED'`. Ignored, with a warning,\n * once the reply has already settled.\n */\n reject(message?: string): void\n /** Aborts when the sender stops waiting for a reply. */\n readonly signal: AbortSignal\n}\n\n/**\n * An observable state topic with access to its current and first values.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusStateSource<T> extends Observable<T> {\n /** Returns the current value, or `undefined` before the first value is published. */\n getCurrent(): T | undefined\n /** Resolves with the first published value. */\n readonly firstValue: Promise<T>\n}\n\n/**\n * Options for aborting a message bus operation.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusAbortOptions {\n /** Aborts the operation when signaled. */\n signal?: AbortSignal\n}\n\n/**\n * Options for reading a state topic.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusQueryOptions extends MessageBusAbortOptions {\n /** Wait timeout in milliseconds. Defaults to 5 seconds; `null` disables it. */\n timeout?: number | null\n}\n\n/**\n * Options for emitting an event topic.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusEmitOptions extends MessageBusAbortOptions {\n /** Reply timeout in milliseconds. Defaults to 5 seconds; `null` disables it. */\n timeout?: number | null\n}\n\n/**\n * A lazily awaited event reply.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusEmitResult<R> extends PromiseLike<R> {\n /** Handles a rejected event reply. */\n catch<T = never>(onRejected?: (reason: unknown) => T | PromiseLike<T>): Promise<R | T>\n /** Runs after the event reply settles. */\n finally(onFinally?: () => void): Promise<R>\n}\n\n/**\n * Sends events and reads typed state and event topics.\n *\n * @remarks\n * State topics are written by the host to each connection separately through\n * {@link MessageBusClient.emit}; a connection only ever reads its own values.\n * @public\n * @category Message Bus\n */\nexport interface MessageBus<TTopics = MessageBusTopics> {\n /** Emits an event topic and provides its reply when awaited. */\n emit<K extends EventTopic<TTopics>>(\n type: K,\n ...rest: PayloadOf<K, TTopics> extends void\n ? [payload?: void, options?: MessageBusEmitOptions]\n : [payload: PayloadOf<K, TTopics>, options?: MessageBusEmitOptions]\n ): MessageBusEmitResult<ReplyOf<K, TTopics>>\n /** Reads the current or next value of a state topic. */\n query<K extends StateTopic<TTopics>>(\n type: K,\n options?: MessageBusQueryOptions,\n ): Promise<ValueOf<K, TTopics>>\n /** Runs a responder for each event until its signal aborts. */\n subscribe<K extends EventTopic<TTopics>>(\n type: K,\n handler: (message: MessageBusMessage<PayloadOf<K, TTopics>, ReplyOf<K, TTopics>, K>) => void,\n options?: MessageBusAbortOptions,\n ): void\n /** Runs a handler for each state value until its signal aborts. */\n subscribe<K extends StateTopic<TTopics>>(\n type: K,\n handler: (value: ValueOf<K, TTopics>) => void,\n options?: MessageBusAbortOptions,\n ): void\n /** Returns a state topic as a `MessageBusStateSource`. */\n subscribe<K extends StateTopic<TTopics>>(type: K): MessageBusStateSource<ValueOf<K, TTopics>>\n /** Returns an event topic as an observable of its payloads. */\n subscribe<K extends EventTopic<TTopics>>(type: K): Observable<PayloadOf<K, TTopics>>\n}\n\n/**\n * A message bus connection that can be torn down independently of its siblings.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusConnection<TTopics = MessageBusTopics> extends MessageBus<TTopics> {\n /** The application this connection belongs to. */\n readonly appId: Application['id']\n /**\n * Tears down this connection: pending requests reject `ABORTED`, subscriptions\n * complete, and later `emit`, `query`, and `subscribe` calls fail with `ABORTED`.\n * Siblings and the shared bus are untouched.\n */\n disconnect(): void\n}\n\n/**\n * The host's handle to one connection: who it is, when it closes, and where to write its state.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusClient {\n /** The application the connection belongs to. */\n readonly appId: Application['id']\n /** The federation module id of the connection. Equals `appId` when the host supplied none. */\n readonly moduleId: string\n /** Aborts when the connection disconnects. Drop per-client state here. */\n readonly closed: AbortSignal\n /** Writes a state value to this connection only. Ignored once the connection has closed. */\n emit<K extends StateTopic>(type: K, value: ValueOf<K>): void\n /**\n * Rejects a state topic for this connection: its pending and later {@link MessageBus.query}\n * calls reject with a {@link MessageBusError} whose `code` is `'REFUSED'`, until the host next\n * writes a value with {@link MessageBusClient.emit}, which clears the rejection.\n *\n * @remarks\n * A rejected promise cannot be un-rejected and an errored subject cannot resume, so the\n * rejection is tracked per connection alongside the topic's subject rather than by erroring\n * it: `query` consults it before awaiting, and {@link MessageBus.subscribe} and the topic's\n * {@link MessageBusStateSource} stay silent (they never error) until a value is written.\n * Ignored once the connection has closed, the same as {@link MessageBusClient.emit}.\n */\n reject<K extends StateTopic>(type: K, message?: string): void\n}\n\n/**\n * The host's connection to the bus.\n *\n * @remarks\n * State reaches an application only through {@link MessageBusClient.emit}. There is no\n * broadcast: sending the same value to everyone is a loop over `connections`, and giving a\n * new connection the current values is done when it appears there, as an SSE server writes\n * a snapshot to each new client.\n * @public\n * @category Message Bus\n */\nexport interface MessageBusHost<TTopics = MessageBusTopics> extends MessageBusConnection<TTopics> {\n /**\n * Every open connection other than this one first, then each new one as it joins. The same\n * {@link MessageBusClient} object is handed out for a connection across subscriptions, so it\n * can be kept in a `Set`. A connection stays listed until it calls `disconnect()`; the SDK\n * does that when the owning `SanityInstance` is disposed.\n */\n readonly connections: Observable<MessageBusClient>\n}\n\nconst MESSAGE_BUS_KEY = Symbol.for('sanity.os.bus')\nconst MESSAGE_BUS_PROTOCOL_KEY = Symbol.for('sanity.os.protocol')\nconst MESSAGE_BUS_REGISTRY_KEY = Symbol.for('sanity.os.registry')\nconst MESSAGE_BUS_PENDING_REPLY_KEY = Symbol.for('sanity.os.request')\n\nconst MESSAGE_BUS_PROTOCOL = 1\n\nconst DEFAULT_TIMEOUT_MS = 5000\n\n// Distinguishes an unpublished topic from a published `undefined` value.\nconst NO_VALUE = Symbol.for('sanity.os.no-value')\n\ntype ReplyOutcome =\n | {readonly ok: true; readonly value: unknown}\n | {readonly ok: false; readonly error: unknown}\n\n// Defers Promise creation until the reply is awaited to preserve fire-and-forget emission.\ninterface PendingReply {\n readonly responderAbort: AbortController\n readonly responderSignal: AbortSignal\n settled: boolean\n outcomeBeforeAwait?: ReplyOutcome\n settlePromise?: (outcome: ReplyOutcome) => void\n replyPromise?: Promise<unknown>\n}\n\n// One connection: its identity, its own copy of every state topic, and its lifetime.\ninterface ConnectionRecord {\n readonly appId: string\n readonly moduleId: string\n readonly stateSubjects: Map<string, BehaviorSubject<unknown>>\n // Topics the host has rejected for this connection, with the reason, until the next write.\n readonly rejections: Map<string, string | undefined>\n // Fires the rejected topic name so pending queries on that topic can reject at once.\n readonly rejected$: Subject<string>\n readonly abort: AbortController\n}\n\ninterface MessageBusRegistry {\n readonly appId: string\n readonly topics: Map<string, TopicManifest[string]>\n readonly connections: Set<ConnectionRecord>\n readonly connected$: Subject<ConnectionRecord>\n readonly eventSubjects: Map<string, Subject<MessageBusMessage<unknown, unknown>>>\n readonly responderCounts: Map<string, number>\n readonly migrations: ReadonlyMap<string, readonly TopicMigration[]>\n resetAbort: AbortController\n generation: number\n}\n\ntype InternalMessageBus = MessageBus & {\n [MESSAGE_BUS_REGISTRY_KEY]: MessageBusRegistry\n [MESSAGE_BUS_PROTOCOL_KEY]: number\n}\n\n// A connection's box for a state topic, created on first use from the topic's manifest seed.\nfunction resolveStateSubject(\n registry: MessageBusRegistry,\n connection: ConnectionRecord,\n type: string,\n): BehaviorSubject<unknown> {\n // Callers gate on the connection's lifetime; this keeps a slipped call from recreating a\n // box on a closed connection that nothing would ever complete.\n if (connection.abort.signal.aborted) throw new MessageBusError('ABORTED')\n let subject = connection.stateSubjects.get(type)\n if (!subject) {\n const topic = registry.topics.get(type)\n if (!topic) {\n console.warn(`[sanity-sdk:message-bus] state topic \"${type}\" is not declared`)\n }\n const seed = topic?.kind === 'state' ? topic.seed : undefined\n subject = new BehaviorSubject<unknown>(seed === undefined ? NO_VALUE : seed)\n connection.stateSubjects.set(type, subject)\n }\n return subject\n}\n\nfunction toStateSource(\n values: Observable<unknown>,\n getCurrent: () => unknown,\n): MessageBusStateSource<unknown> {\n const source = values as MessageBusStateSource<unknown>\n source.getCurrent = getCurrent\n // Unread sources must not create promises that reject when reset completes them.\n let firstValue: Promise<unknown> | undefined\n Object.defineProperty(source, 'firstValue', {\n get: () => (firstValue ??= firstValueFrom(values)),\n })\n return source\n}\n\nfunction assertCompatibleTopicManifest(\n registry: MessageBusRegistry,\n manifest: TopicManifest,\n): void {\n for (const [type, entry] of Object.entries(manifest)) {\n const existing = registry.topics.get(type)\n if (existing && existing.kind !== entry.kind) {\n throw new MessageBusError(\n 'PROTOCOL_MISMATCH',\n `topic \"${type}\" is declared \"${entry.kind}\" but the installed bus knows it as \"${existing.kind}\"`,\n )\n }\n if (\n existing?.kind === 'event' &&\n entry.kind === 'event' &&\n existing.ownership.type !== entry.ownership.type\n ) {\n throw new MessageBusError('OWNERSHIP_MISMATCH', `topic \"${type}\" has conflicting ownership`)\n }\n }\n}\n\nfunction mergeTopicManifest(registry: MessageBusRegistry, manifest: TopicManifest): void {\n assertCompatibleTopicManifest(registry, manifest)\n for (const [type, entry] of Object.entries(manifest)) registry.topics.set(type, entry)\n}\n\nfunction resolveEventSubject(\n registry: MessageBusRegistry,\n type: string,\n): Subject<MessageBusMessage<unknown, unknown>> {\n let subject = registry.eventSubjects.get(type)\n if (!subject) {\n subject = new Subject<MessageBusMessage<unknown, unknown>>()\n registry.eventSubjects.set(type, subject)\n }\n return subject\n}\n\nfunction settleReply(reply: PendingReply, outcome: ReplyOutcome): void {\n if (reply.settled) return\n reply.settled = true\n if (reply.settlePromise) reply.settlePromise(outcome)\n else reply.outcomeBeforeAwait = outcome\n}\n\nfunction createEventMessage(\n appId: string,\n moduleId: string,\n type: string,\n payload: unknown,\n pendingReply: PendingReply,\n): MessageBusMessage<unknown, unknown> {\n const message: MessageBusMessage<unknown, unknown> & {\n [MESSAGE_BUS_PENDING_REPLY_KEY]?: PendingReply\n } = {\n type: type as TopicName,\n payload,\n meta: {appId, moduleId, timestamp: Date.now()},\n reply: (value) => {\n if (pendingReply.settled) {\n console.warn(\n `[sanity-sdk:message-bus] reply ignored for \"${type}\": no waiting caller or already replied`,\n )\n return\n }\n settleReply(pendingReply, {ok: true, value})\n },\n reject: (reason) => {\n if (pendingReply.settled) {\n console.warn(\n `[sanity-sdk:message-bus] reject ignored for \"${type}\": no waiting caller or already replied`,\n )\n return\n }\n settleReply(pendingReply, {ok: false, error: new MessageBusError('REFUSED', reason)})\n },\n get signal() {\n return pendingReply.responderSignal\n },\n }\n\n message[MESSAGE_BUS_PENDING_REPLY_KEY] = pendingReply\n return message\n}\n\nfunction createReplyPromise(\n pendingReply: PendingReply,\n options: MessageBusEmitOptions & {hadResponderAtEmission: boolean},\n): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n const settlePromise = (outcome: ReplyOutcome) =>\n outcome.ok ? resolve(outcome.value) : reject(outcome.error)\n\n if (pendingReply.outcomeBeforeAwait) {\n pendingReply.responderAbort.abort()\n settlePromise(pendingReply.outcomeBeforeAwait)\n return\n }\n if (!options.hadResponderAtEmission) {\n reject(new MessageBusError('NO_RESPONDER'))\n return\n }\n\n const timeoutMs = options.timeout === undefined ? DEFAULT_TIMEOUT_MS : options.timeout\n let timer: ReturnType<typeof setTimeout> | undefined\n const onAbort = () =>\n settleReply(pendingReply, {ok: false, error: new MessageBusError('ABORTED')})\n\n pendingReply.settlePromise = (outcome) => {\n if (timer !== undefined) clearTimeout(timer)\n options.signal?.removeEventListener('abort', onAbort)\n pendingReply.responderAbort.abort()\n settlePromise(outcome)\n }\n\n if (timeoutMs !== null) {\n timer = setTimeout(\n () => settleReply(pendingReply, {ok: false, error: new MessageBusError('TIMEOUT')}),\n timeoutMs,\n )\n }\n if (options.signal) {\n if (options.signal.aborted) onAbort()\n else options.signal.addEventListener('abort', onAbort, {once: true})\n }\n })\n}\n\nfunction createLazyReply<R>(awaitReply: () => Promise<R>): MessageBusEmitResult<R> {\n return {\n // oxlint-disable-next-line unicorn/no-thenable -- awaiting arms reply failure handling; fire-and-forget does not.\n then: (onFulfilled, onRejected) => awaitReply().then(onFulfilled, onRejected),\n catch: (onRejected) => awaitReply().then(undefined, onRejected),\n finally: (onFinally) => awaitReply().finally(onFinally),\n }\n}\n\nfunction emitEvent(\n registry: MessageBusRegistry,\n type: string,\n payload: unknown,\n options: MessageBusEmitOptions | undefined,\n appId: string,\n moduleId: string,\n): MessageBusEmitResult<unknown> {\n const hadResponderAtEmission = (registry.responderCounts.get(type) ?? 0) > 0\n const responderAbort = new AbortController()\n const pendingReply: PendingReply = {\n responderAbort,\n responderSignal: scopeSignal(options?.signal, responderAbort.signal),\n settled: false,\n }\n\n resolveEventSubject(registry, type).next(\n createEventMessage(appId, moduleId, type, payload, pendingReply),\n )\n\n const awaitReply = () =>\n (pendingReply.replyPromise ??= createReplyPromise(pendingReply, {\n ...options,\n hadResponderAtEmission,\n }))\n return createLazyReply(awaitReply)\n}\n\nconst isStateTopic = (registry: MessageBusRegistry, type: string): boolean =>\n registry.topics.get(type)?.kind === 'state'\n\nconst canRespond = (\n registry: MessageBusRegistry,\n ownership: {readonly type: 'same_app' | 'any_app'},\n appId: string,\n): boolean => ownership.type === 'any_app' || appId === registry.appId\n\nfunction emit(\n registry: MessageBusRegistry,\n type: string,\n payload: unknown,\n options: MessageBusEmitOptions | undefined,\n appId: string,\n moduleId: string,\n connectionSignal: AbortSignal,\n): MessageBusEmitResult<unknown> {\n if (isStateTopic(registry, type)) {\n throw new MessageBusError(\n 'OWNERSHIP_MISMATCH',\n `Cannot emit state topic \"${type}\" from app \"${appId}\". The host writes state to each connection through its client handle. Read it with query() or subscribe().`,\n )\n }\n return emitEvent(\n registry,\n type,\n payload,\n {\n ...options,\n signal: scopeSignal(options?.signal, registry.resetAbort.signal, connectionSignal),\n },\n appId,\n moduleId,\n )\n}\n\nfunction emitState(\n registry: MessageBusRegistry,\n connection: ConnectionRecord,\n type: string,\n value: unknown,\n): void {\n // A written value clears any rejection so later queries resolve normally.\n connection.rejections.delete(type)\n const subject = resolveStateSubject(registry, connection, type)\n if (!Object.is(subject.getValue(), value)) subject.next(value)\n}\n\nfunction query(\n source: MessageBusStateSource<unknown>,\n type: string,\n options: MessageBusQueryOptions | undefined,\n connectionSignal: AbortSignal,\n resetSignal: AbortSignal,\n connection: ConnectionRecord,\n): Promise<unknown> {\n const rejection = () => new MessageBusError('REFUSED', connection.rejections.get(type))\n // A rejection outranks any earlier value: it is cleared only when the host writes a new one.\n if (connection.rejections.has(type)) return Promise.reject(rejection())\n const current = source.getCurrent()\n if (current !== undefined) return Promise.resolve(current)\n\n const signal = scopeSignal(options?.signal, resetSignal, connectionSignal)\n if (signal.aborted) return Promise.reject(new MessageBusError('ABORTED'))\n const timeoutMs = options?.timeout === undefined ? DEFAULT_TIMEOUT_MS : options.timeout\n return new Promise((resolve, reject) => {\n const timer =\n timeoutMs === null\n ? undefined\n : setTimeout(() => {\n clear()\n signal?.removeEventListener('abort', onAbort)\n reject(new MessageBusError('TIMEOUT', `query(\"${type}\") timed out`))\n }, timeoutMs)\n // A rejection that arrives while waiting rejects the pending query at once.\n const rejectedSub = connection.rejected$.subscribe((rejectedType) => {\n if (rejectedType !== type) return\n clear()\n signal?.removeEventListener('abort', onAbort)\n reject(rejection())\n })\n const clear = () => {\n if (timer !== undefined) clearTimeout(timer)\n rejectedSub.unsubscribe()\n }\n const onAbort = () => {\n clear()\n reject(new MessageBusError('ABORTED'))\n }\n signal?.addEventListener('abort', onAbort, {once: true})\n void source.firstValue.then(\n (value) => {\n clear()\n signal?.removeEventListener('abort', onAbort)\n resolve(value)\n },\n (error) => {\n clear()\n signal?.removeEventListener('abort', onAbort)\n reject(error)\n },\n )\n })\n}\n\nfunction unsubscribeOnAbort(subscription: Subscription, signal: AbortSignal | undefined): void {\n if (!signal) return\n if (signal.aborted) {\n subscription.unsubscribe()\n return\n }\n signal.addEventListener('abort', () => subscription.unsubscribe(), {\n once: true,\n })\n}\n\nfunction scopeSignal(signal: AbortSignal | undefined, ...lifecycles: AbortSignal[]): AbortSignal {\n return signal ? AbortSignal.any([signal, ...lifecycles]) : AbortSignal.any(lifecycles)\n}\n\nfunction invokeResponder(\n handler: (message: MessageBusMessage<unknown, unknown>) => unknown,\n message: MessageBusMessage<unknown, unknown> & {\n [MESSAGE_BUS_PENDING_REPLY_KEY]?: PendingReply\n },\n): void {\n const pendingReply = message[MESSAGE_BUS_PENDING_REPLY_KEY]\n const fail = (error: unknown) => {\n if (pendingReply) {\n settleReply(pendingReply, {\n ok: false,\n error: new MessageBusError('HANDLER_THREW', undefined, {\n cause: error,\n }),\n })\n }\n }\n try {\n const result = handler(message)\n if (result instanceof Promise) result.catch(fail)\n } catch (error) {\n fail(error)\n }\n}\n\nfunction respond(\n registry: MessageBusRegistry,\n type: string,\n handler: (message: MessageBusMessage<unknown, unknown>) => unknown,\n options: MessageBusAbortOptions | undefined,\n appId: string,\n connectionSignal: AbortSignal,\n): void {\n const topic = registry.topics.get(type)\n if (topic?.kind === 'event' && !canRespond(registry, topic.ownership, appId)) {\n throw new MessageBusError(\n 'OWNERSHIP_MISMATCH',\n `Cannot register a handler for event topic \"${type}\" from app \"${appId}\". Only the app that owns this topic can respond to it. Other apps can send it with emit().`,\n )\n }\n\n registry.responderCounts.set(type, (registry.responderCounts.get(type) ?? 0) + 1)\n const subscription = resolveEventSubject(registry, type).subscribe((message) =>\n invokeResponder(handler, message),\n )\n subscription.add(() => {\n const count = registry.responderCounts.get(type) ?? 0\n if (count > 0) registry.responderCounts.set(type, count - 1)\n })\n unsubscribeOnAbort(\n subscription,\n scopeSignal(options?.signal, registry.resetAbort.signal, connectionSignal),\n )\n}\n\nconst bundledMigrations = () => new Map(Object.entries(topicMigrations))\n\n/**\n * Creates an isolated message bus without installing it globally and returns the host's\n * connection to it.\n * @internal\n */\nexport function createIsolatedMessageBus(\n appId: string,\n config: {\n migrations?: ReadonlyMap<string, readonly TopicMigration[]>\n } = {},\n): MessageBusHost<Topics> {\n if (!appId) throwMissingAppId()\n\n const registry: MessageBusRegistry = {\n appId,\n topics: new Map(),\n connections: new Set(),\n connected$: new Subject(),\n eventSubjects: new Map(),\n responderCounts: new Map(),\n migrations: config.migrations ?? bundledMigrations(),\n resetAbort: new AbortController(),\n generation: 0,\n }\n\n mergeTopicManifest(registry, DASHBOARD_TOPIC_MANIFEST)\n\n return createConnection(registry, {\n appId,\n migrations: config.migrations,\n }) as MessageBusHost<Topics>\n}\n\ntype TopicVersionAdapter = {\n toInstalled: (type: string, value: unknown) => unknown\n toApplication: (type: string, value: unknown) => unknown\n}\n\ntype TopicCompatibility = {\n toInstalledEmission: TopicVersionAdapter['toInstalled']\n toApplicationStateValue: TopicVersionAdapter['toApplication']\n toApplicationEventPayload: TopicVersionAdapter['toApplication']\n toInstalledEventReply: TopicVersionAdapter['toInstalled']\n toApplicationEventReply: TopicVersionAdapter['toApplication']\n}\n\ntype TopicMigrationTransform = Pick<TopicMigration, 'up' | 'down'>\n\nconst identityMigration: TopicMigrationTransform = {\n up: (value) => value,\n down: (value) => value,\n}\n\nfunction effectiveTopicVersions(\n migrations: ReadonlyMap<string, readonly TopicMigration[]>,\n): Map<string, number> {\n const versions = new Map<string, number>()\n for (const [topic, steps] of migrations) {\n let version = 1\n for (const step of steps) if (step.to > version) version = step.to\n versions.set(topic, version)\n }\n return versions\n}\n\nfunction migrationTransformAt(\n steps: readonly TopicMigration[] | undefined,\n version: number,\n select: (step: TopicMigration) => TopicMigrationTransform | undefined,\n): TopicMigrationTransform {\n const step = steps?.find((candidate) => candidate.from === version)\n return (step ? select(step) : undefined) ?? identityMigration\n}\n\nfunction migrateVersionedValue(\n steps: readonly TopicMigration[] | undefined,\n value: unknown,\n from: number,\n to: number,\n select: (step: TopicMigration) => TopicMigrationTransform | undefined,\n): unknown {\n if (from === to) return value\n\n let current = value\n if (from < to) {\n for (let version = from; version < to; version++) {\n current = migrationTransformAt(steps, version, select).up(current)\n }\n } else {\n for (let version = from; version > to; version--) {\n current = migrationTransformAt(steps, version - 1, select).down(current)\n }\n }\n return current\n}\n\nfunction createTopicCompatibility(\n installedMigrations: ReadonlyMap<string, readonly TopicMigration[]>,\n applicationMigrations: ReadonlyMap<string, readonly TopicMigration[]>,\n): TopicCompatibility {\n const installedVersions = effectiveTopicVersions(installedMigrations)\n const applicationVersions = effectiveTopicVersions(applicationMigrations)\n const applicationVersion = (type: string) => applicationVersions.get(type) ?? 1\n const installedVersion = (type: string) => installedVersions.get(type) ?? 1\n const migrationChainFor = (type: string) =>\n (applicationVersion(type) > installedVersion(type)\n ? applicationMigrations\n : installedMigrations\n ).get(type)\n const createVersionAdapter = (\n select: (step: TopicMigration) => TopicMigrationTransform | undefined,\n ): TopicVersionAdapter => ({\n toInstalled: (type, value) =>\n migrateVersionedValue(\n migrationChainFor(type),\n value,\n applicationVersion(type),\n installedVersion(type),\n select,\n ),\n toApplication: (type, value) =>\n migrateVersionedValue(\n migrationChainFor(type),\n value,\n installedVersion(type),\n applicationVersion(type),\n select,\n ),\n })\n\n const stateValueAndEventPayload = createVersionAdapter((step) => step)\n const eventReply = createVersionAdapter((step) => step.reply)\n return {\n toInstalledEmission: stateValueAndEventPayload.toInstalled,\n toApplicationStateValue: stateValueAndEventPayload.toApplication,\n toApplicationEventPayload: stateValueAndEventPayload.toApplication,\n toInstalledEventReply: eventReply.toInstalled,\n toApplicationEventReply: eventReply.toApplication,\n }\n}\n\n// Cache projections by input reference to keep state snapshots stable.\nfunction projectCurrent(input: () => unknown, project: (value: unknown) => unknown): () => unknown {\n let lastInput: unknown\n let lastOutput: unknown\n let cached = false\n return () => {\n const current = input()\n if (current === undefined) return undefined\n if (!cached || current !== lastInput) {\n lastInput = current\n lastOutput = project(current)\n cached = true\n }\n return lastOutput\n }\n}\n\n// The connection's view of one of its state boxes, in the connection's topic version.\nfunction createStateSource(\n subject: BehaviorSubject<unknown>,\n project: (value: unknown) => unknown,\n completeOn: Observable<unknown>,\n): MessageBusStateSource<unknown> {\n const getCurrent = () => {\n const current = subject.getValue()\n return current === NO_VALUE ? undefined : current\n }\n return toStateSource(\n subject.pipe(\n filter((value) => value !== NO_VALUE),\n map(project),\n takeUntil(completeOn),\n ),\n projectCurrent(getCurrent, project),\n )\n}\n\nfunction migrateEventMessage(\n message: MessageBusMessage<unknown, unknown>,\n payload: (value: unknown) => unknown,\n reply: (value: unknown) => unknown,\n): MessageBusMessage<unknown, unknown> {\n return {\n type: message.type,\n payload: payload(message.payload),\n meta: message.meta,\n reply: (value) => message.reply(reply(value)),\n reject: (reason) => message.reject(reason),\n get signal() {\n return message.signal\n },\n }\n}\n\nfunction migrateEventReply(\n result: MessageBusEmitResult<unknown>,\n project: (value: unknown) => unknown,\n): MessageBusEmitResult<unknown> {\n let projected: Promise<unknown> | undefined\n return createLazyReply(() => (projected ??= Promise.resolve(result).then(project)))\n}\n\nfunction createRejectedConnection(\n appId: string,\n connectionError: () => unknown,\n): MessageBusConnection {\n const throwConnectionError = (): never => {\n throw connectionError()\n }\n return {\n appId,\n emit: throwConnectionError,\n // `query` is typed as a Promise, so it must reject rather than throw synchronously.\n query: () => Promise.reject(connectionError()),\n subscribe: throwConnectionError,\n disconnect: () => {},\n } as unknown as MessageBusConnection\n}\n\n/**\n * Options for connecting an application to an isolated message bus.\n * @internal\n */\nexport interface ConnectApplicationToMessageBusOptions {\n /** The application ID stamped on emitted messages. */\n appId: string\n /** The federation module id stamped on emitted messages. Defaults to `appId`. */\n moduleId?: string\n /** The topic migrations supported by the application. */\n migrations?: ReadonlyMap<string, readonly TopicMigration[]>\n}\n\n/**\n * Connects an application to an isolated message bus.\n * @internal\n */\nexport function connectApplicationToMessageBus(\n installedMessageBus: MessageBus,\n config: ConnectApplicationToMessageBusOptions,\n): MessageBusConnection<Topics> {\n if (!config.appId) throwMissingAppId()\n\n const {appId} = config\n const installedProtocol = (installedMessageBus as Partial<InternalMessageBus>)[\n MESSAGE_BUS_PROTOCOL_KEY\n ]\n if (installedProtocol !== MESSAGE_BUS_PROTOCOL) {\n console.error(\n `[sanity-sdk:message-bus] protocol mismatch for \"${appId}\": installed ${String(installedProtocol)}, this copy speaks ${MESSAGE_BUS_PROTOCOL}`,\n )\n return createRejectedConnection(\n appId,\n () =>\n new MessageBusError(\n 'PROTOCOL_MISMATCH',\n `installed message bus speaks protocol ${String(installedProtocol)}, this copy speaks ${MESSAGE_BUS_PROTOCOL}`,\n ),\n )\n }\n\n const registry = (installedMessageBus as Partial<InternalMessageBus>)[MESSAGE_BUS_REGISTRY_KEY]\n if (!registry) {\n console.error(`[sanity-sdk:message-bus] incompatible message bus for \"${appId}\"`)\n return createRejectedConnection(\n appId,\n () =>\n new MessageBusError(\n 'PROTOCOL_MISMATCH',\n 'installed message bus does not expose a compatible registry',\n ),\n )\n }\n\n try {\n mergeTopicManifest(registry, DASHBOARD_TOPIC_MANIFEST)\n } catch (error) {\n console.error(`[sanity-sdk:message-bus] topic manifest conflict for \"${appId}\"`, {error})\n return createRejectedConnection(appId, () => error)\n }\n\n return createConnection(registry, config) as MessageBusConnection<Topics>\n}\n\n// Hands the host the same client object for a connection across `connections` subscriptions.\nfunction createClient(\n registry: MessageBusRegistry,\n record: ConnectionRecord,\n compatibility: TopicCompatibility,\n): MessageBusClient {\n return {\n appId: record.appId,\n moduleId: record.moduleId,\n closed: record.abort.signal,\n emit: (type: string, value: unknown) => {\n if (record.abort.signal.aborted) {\n console.warn(\n `[sanity-sdk:message-bus] \"${type}\" not written: connection \"${record.moduleId}\" has closed`,\n )\n return\n }\n emitState(registry, record, type, compatibility.toInstalledEmission(type, value))\n },\n reject: (type: string, message?: string) => {\n if (record.abort.signal.aborted) return\n record.rejections.set(type, message)\n record.rejected$.next(type)\n },\n } as MessageBusClient\n}\n\n// Open connections other than the host's own first, then each new one; one client object per\n// connection so the host can keep them in a Set. Completes when the host connection disconnects.\nfunction createConnectionsSource(\n registry: MessageBusRegistry,\n self: ConnectionRecord,\n compatibility: TopicCompatibility,\n completeOn: Observable<unknown>,\n): Observable<MessageBusClient> {\n const clients = new WeakMap<ConnectionRecord, MessageBusClient>()\n const clientFor = (record: ConnectionRecord) => {\n let client = clients.get(record)\n if (!client) {\n client = createClient(registry, record, compatibility)\n clients.set(record, client)\n }\n return client\n }\n return defer(() => concat(from([...registry.connections]), registry.connected$)).pipe(\n filter((record) => record !== self),\n map(clientFor),\n takeUntil(completeOn),\n )\n}\n\nfunction createConnection(\n registry: MessageBusRegistry,\n config: ConnectApplicationToMessageBusOptions,\n): MessageBusConnection {\n const {appId} = config\n const moduleId = config.moduleId ?? appId\n // Each connection owns its lifetime; disconnect() aborts it without touching siblings.\n const connectionAbort = new AbortController()\n const connectionSignal = connectionAbort.signal\n // ReplaySubject, not fromEvent: `abort` fires once, so a cold listener attached by a\n // stream subscribed after disconnect() would never see it and never complete. Replaying\n // the notification lets those late subscribers complete immediately.\n const connectionAborted$ = new ReplaySubject<void>(1)\n connectionSignal.addEventListener('abort', () => connectionAborted$.next(), {once: true})\n\n const record: ConnectionRecord = {\n appId,\n moduleId,\n stateSubjects: new Map(),\n rejections: new Map(),\n rejected$: new Subject<string>(),\n abort: connectionAbort,\n }\n\n const compatibility = createTopicCompatibility(\n registry.migrations,\n config.migrations ?? bundledMigrations(),\n )\n const isState = (type: string) => isStateTopic(registry, type)\n\n // Reuse topic streams because React external-store snapshots require stable references.\n const applicationStreams = new Map<string, MessageBusStateSource<unknown> | Observable<unknown>>()\n let streamGeneration = registry.generation\n const cachedStream = <T extends MessageBusStateSource<unknown> | Observable<unknown>>(\n type: string,\n create: () => T,\n ): T => {\n if (streamGeneration !== registry.generation) {\n applicationStreams.clear()\n streamGeneration = registry.generation\n }\n let stream = applicationStreams.get(type)\n if (!stream) {\n stream = create()\n applicationStreams.set(type, stream)\n }\n return stream as T\n }\n const stateSource = (type: string) =>\n cachedStream(type, () =>\n createStateSource(\n resolveStateSubject(registry, record, type),\n (value) => compatibility.toApplicationStateValue(type, value),\n connectionAborted$,\n ),\n )\n const eventStream = (type: string) =>\n cachedStream(type, () =>\n resolveEventSubject(registry, type).pipe(\n map((message) => compatibility.toApplicationEventPayload(type, message.payload)),\n takeUntil(connectionAborted$),\n ),\n )\n\n // A disconnected connection must not reach siblings, so its operations fail before touching\n // the shared registry rather than only tearing down pending requests and subscriptions.\n const throwIfDisconnected = () => {\n if (connectionSignal.aborted) throw new MessageBusError('ABORTED')\n }\n\n const connection = {\n appId,\n emit: (type: string, payload: unknown, options?: MessageBusEmitOptions) => {\n throwIfDisconnected()\n return migrateEventReply(\n emit(\n registry,\n type,\n compatibility.toInstalledEmission(type, payload),\n options,\n appId,\n moduleId,\n connectionSignal,\n ),\n (value) => compatibility.toApplicationEventReply(type, value),\n )\n },\n query: (type: string, options?: MessageBusQueryOptions) => {\n if (connectionSignal.aborted) return Promise.reject(new MessageBusError('ABORTED'))\n return query(\n stateSource(type),\n type,\n options,\n connectionSignal,\n registry.resetAbort.signal,\n record,\n )\n },\n subscribe: (\n type: string,\n handler?: (arg: never) => void,\n options?: MessageBusAbortOptions,\n ): MessageBusStateSource<unknown> | Observable<unknown> | undefined => {\n throwIfDisconnected()\n if (isState(type)) {\n const source = stateSource(type)\n if (!handler) return source\n unsubscribeOnAbort(\n source.subscribe(handler as (value: unknown) => void),\n scopeSignal(options?.signal, registry.resetAbort.signal, connectionSignal),\n )\n return undefined\n }\n if (!handler) return eventStream(type)\n respond(\n registry,\n type,\n (message) =>\n (handler as (message: MessageBusMessage<unknown, unknown>) => void)(\n migrateEventMessage(\n message,\n (value) => compatibility.toApplicationEventPayload(type, value),\n (value) => compatibility.toInstalledEventReply(type, value),\n ),\n ),\n options,\n appId,\n connectionSignal,\n )\n return undefined\n },\n disconnect: () => {\n if (connectionSignal.aborted) return\n connectionAbort.abort()\n for (const subject of record.stateSubjects.values()) subject.complete()\n record.stateSubjects.clear()\n record.rejected$.complete()\n registry.connections.delete(record)\n },\n }\n\n if (appId === registry.appId) {\n Object.assign(connection, {\n connections: createConnectionsSource(registry, record, compatibility, connectionAborted$),\n })\n }\n\n const instance = connection as unknown as InternalMessageBus\n instance[MESSAGE_BUS_REGISTRY_KEY] = registry\n instance[MESSAGE_BUS_PROTOCOL_KEY] = MESSAGE_BUS_PROTOCOL\n\n // Announce last: a host subscriber may write to the new client synchronously.\n registry.connections.add(record)\n registry.connected$.next(record)\n return instance as unknown as MessageBusConnection\n}\n\nfunction reset(registry: MessageBusRegistry): void {\n registry.resetAbort.abort()\n for (const connection of registry.connections) {\n for (const subject of connection.stateSubjects.values()) subject.complete()\n connection.stateSubjects.clear()\n connection.rejections.clear()\n }\n for (const subject of registry.eventSubjects.values()) subject.complete()\n\n registry.topics.clear()\n registry.eventSubjects.clear()\n registry.responderCounts.clear()\n registry.resetAbort = new AbortController()\n registry.generation += 1\n mergeTopicManifest(registry, DASHBOARD_TOPIC_MANIFEST)\n}\n\ndeclare const __SANITY_APP_ID__: string | undefined\n\nfunction throwMissingAppId(): never {\n throw new MessageBusError(\n 'MISSING_APP_ID',\n 'Cannot initialize the message bus without an app ID. Build the application with the Sanity CLI or pass an app ID when connecting.',\n )\n}\n\nconst resolveAppId = (appId?: string): string | undefined =>\n appId ?? (typeof __SANITY_APP_ID__ === 'string' ? __SANITY_APP_ID__ : undefined)\n\nfunction getInstalledMessageBus(): MessageBus | undefined {\n const bus = (globalThis as {[MESSAGE_BUS_KEY]?: unknown})[MESSAGE_BUS_KEY]\n return typeof bus === 'object' && bus !== null && MESSAGE_BUS_REGISTRY_KEY in bus\n ? (bus as unknown as MessageBus)\n : undefined\n}\n\n/**\n * Returns whether a message bus registry is installed.\n * @internal\n */\nexport function isMessageBusInstalled(): boolean {\n return getInstalledMessageBus() !== undefined\n}\n\n/**\n * Returns whether this application installed the message bus and hosts the others on it.\n * @internal\n */\nexport function isMessageBusHost(): boolean {\n const installedMessageBus = getInstalledMessageBus()\n return (\n !!installedMessageBus &&\n (installedMessageBus as InternalMessageBus)[MESSAGE_BUS_REGISTRY_KEY].appId === resolveAppId()\n )\n}\n\n/**\n * Returns whether this application runs on an installed message bus.\n * @internal\n */\nexport function isMessageBusEnvironment(): boolean {\n return isMessageBusInstalled()\n}\n\n/**\n * Options for connecting to an installed message bus.\n * @public\n * @category Message Bus\n */\nexport interface ConnectMessageBusOptions {\n /** The application ID. Defaults to the ID embedded by the Sanity CLI. */\n appId?: string\n /** The federation module id stamped on emitted messages. Defaults to `appId`. */\n moduleId?: string\n}\n\n/**\n * Connects to the installed message bus, or returns `undefined` when no compatible connection exists.\n * @public\n * @category Message Bus\n */\nexport function connectMessageBus(\n options: ConnectMessageBusOptions = {},\n): MessageBusConnection | undefined {\n const installedMessageBus = getInstalledMessageBus()\n if (!installedMessageBus) return undefined\n\n const appId = resolveAppId(options.appId)\n if (!appId) {\n console.warn(\n '[sanity-sdk:message-bus] cannot connect without an app ID; build with the Sanity CLI or pass appId',\n )\n return undefined\n }\n\n const connection = connectApplicationToMessageBus(installedMessageBus, {\n appId,\n moduleId: options.moduleId,\n })\n return MESSAGE_BUS_REGISTRY_KEY in connection ? connection : undefined\n}\n\n/**\n * Resets the installed message bus for test isolation.\n * @internal\n */\nexport function resetMessageBus(): void {\n const installedMessageBus = getInstalledMessageBus()\n if (!installedMessageBus) return\n reset((installedMessageBus as InternalMessageBus)[MESSAGE_BUS_REGISTRY_KEY])\n}\n\n/**\n * Options for installing the shared message bus. The host is the whole app, so it carries\n * no `moduleId`.\n * @internal\n */\nexport interface InstallMessageBusOptions {\n /** The application ID. Defaults to the ID embedded by the Sanity CLI. */\n appId?: string\n}\n\n/**\n * Installs the shared message bus and returns the host's connection, or connects to its\n * existing installation. Only the host calls this; another app's ID is rejected because the\n * connection it would get has no `connections`.\n * @internal\n */\nexport function installMessageBus(options: InstallMessageBusOptions = {}): MessageBusHost<Topics> {\n const appId = resolveAppId(options.appId) ?? throwMissingAppId()\n const installedMessageBus = getInstalledMessageBus()\n if (installedMessageBus) {\n const installedAppId = (installedMessageBus as InternalMessageBus)[MESSAGE_BUS_REGISTRY_KEY]\n .appId\n if (installedAppId !== appId) {\n throw new MessageBusError(\n 'OWNERSHIP_MISMATCH',\n `Cannot install the message bus as \"${appId}\": it is already installed by \"${installedAppId}\". Applications connect with connectMessageBus().`,\n )\n }\n return connectApplicationToMessageBus(installedMessageBus, {\n appId,\n }) as MessageBusHost<Topics>\n }\n\n const globals = globalThis as {[MESSAGE_BUS_KEY]?: MessageBus}\n if (globals[MESSAGE_BUS_KEY]) {\n // A foreign value already occupies the bus symbol (e.g. an older Workbench bus); overwriting it disconnects that bus.\n console.error(\n '[sanity-sdk:message-bus] overwriting an incompatible message bus already installed',\n )\n }\n const host = createIsolatedMessageBus(appId)\n globals[MESSAGE_BUS_KEY] = host\n return host\n}\n\n/**\n * Declares state topics that are not in the bundled manifest, with the seed a new\n * connection's box starts from.\n * @internal\n */\nexport function registerStateTopics(\n target: MessageBus,\n topics: Partial<{[K in StateTopic]: ValueOf<K> | undefined}>,\n): void {\n const registry = (target as InternalMessageBus)[MESSAGE_BUS_REGISTRY_KEY]\n const manifest: TopicManifest = Object.fromEntries(\n Object.entries(topics).map(([name, seed]) => [name, {kind: 'state', seed}]),\n )\n mergeTopicManifest(registry, manifest)\n}\n","export const DEFAULT_BASE = 'http://localhost'\nexport const AUTH_CODE_PARAM = 'sid'\nexport const DEFAULT_API_VERSION = '2021-06-07'\nexport const REQUEST_TAG_PREFIX = 'sanity.sdk.auth'\n","import {type SanityConfig} from '../config/sanityConfig'\nimport {isMessageBusEnvironment, isMessageBusHost} from '../dashboard/messageBus/bus'\nimport {DEFAULT_BASE} from './authConstants'\n\n/**\n * The runtime auth mode determines which authentication strategy the SDK uses.\n *\n * - `studio` — Running inside Sanity Studio. Token is discovered from\n * Studio's localStorage entry or via cookie auth.\n * - `oauth` — Configured with `auth.oauth`. Authenticates via Sanity's\n * OAuth 2.0 authorization-code + PKCE flow.\n * - `dashboard` — Running inside the Sanity Dashboard iframe. Token is\n * provided by the parent frame via Comlink.\n * - `standalone` — Running as an independent app. Token comes from\n * localStorage or the OAuth login flow.\n *\n * @internal\n */\ntype AuthMode = 'studio' | 'oauth' | 'dashboard' | 'standalone'\n\n/**\n * Determines the auth mode from instance config and environment.\n *\n * Priority:\n * 1. `studio` config provided → `'studio'`\n * 2. `auth.oauth` config provided → `'oauth'` (explicit config wins over\n * environment detection)\n * 3. Dashboard context detected (`_context` URL param with content) → `'dashboard'`\n * 4. Otherwise → `'standalone'`\n *\n * @internal\n */\nexport function resolveAuthMode(config: SanityConfig, locationHref: string): AuthMode {\n if (isStudioConfig(config)) return 'studio'\n if (config.auth?.oauth) return 'oauth'\n if ((isMessageBusEnvironment() && !isMessageBusHost()) || detectDashboardContext(locationHref)) {\n return 'dashboard'\n }\n return 'standalone'\n}\n\n/**\n * Returns `true` when the config indicates the SDK is running inside a Studio.\n *\n * @internal\n */\nexport function isStudioConfig(config: SanityConfig): boolean {\n return !!config.studio\n}\n\n/**\n * Checks whether the given location href contains a `_context` URL parameter\n * with a non-empty JSON object, indicating the SDK is running inside the\n * Sanity Dashboard.\n *\n * @internal\n */\nfunction detectDashboardContext(locationHref: string): boolean {\n try {\n const parsedUrl = new URL(locationHref, DEFAULT_BASE)\n const contextParam = parsedUrl.searchParams.get('_context')\n if (!contextParam) return false\n\n const parsed: unknown = JSON.parse(contextParam)\n return (\n typeof parsed === 'object' &&\n parsed !== null &&\n !Array.isArray(parsed) &&\n Object.keys(parsed as Record<string, unknown>).length > 0\n )\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('Failed to parse dashboard context from initial location:', err)\n return false\n }\n}\n","/**\n * Represents the various states the authentication type can be in.\n *\n * @public\n */\nexport enum AuthStateType {\n LOGGED_IN = 'logged-in',\n LOGGING_IN = 'logging-in',\n ERROR = 'error',\n LOGGED_OUT = 'logged-out',\n}\n","import {\n distinctUntilChanged,\n exhaustMap,\n filter,\n map,\n Observable,\n type Subscription,\n switchMap,\n takeWhile,\n timer,\n} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'\nimport {getAuthLogger} from './authLogger'\nimport {AuthStateType} from './authStateType'\nimport {type AuthState, type AuthStoreState} from './authStore'\n\nconst REFRESH_INTERVAL = 12 * 60 * 60 * 1000 // 12 hours in milliseconds\n\nfunction createTokenRefreshStream(\n token: string,\n clientFactory: AuthStoreState['options']['clientFactory'],\n apiHost: string | undefined,\n): Observable<{token: string}> {\n return new Observable((subscriber) => {\n const client = clientFactory({\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n useProjectHostname: false,\n useCdn: false,\n token,\n ignoreBrowserTokenWarning: true,\n ...(apiHost && {apiHost}),\n })\n\n const subscription = client.observable\n .request<{token: string}>({\n url: 'auth/refresh-token',\n method: 'POST',\n tag: 'refresh-token',\n body: {\n token,\n },\n })\n .subscribe(subscriber)\n\n return () => subscription.unsubscribe()\n })\n}\n\nfunction shouldRefreshToken(lastRefresh: number | undefined): boolean {\n if (!lastRefresh) return true\n const timeSinceLastRefresh = Date.now() - lastRefresh\n return timeSinceLastRefresh >= REFRESH_INTERVAL\n}\n\n/**\n * Periodically refreshes stamped auth tokens (those containing `-st`).\n *\n * Two triggers cause a refresh while the user stays logged in:\n * - a 12-hour interval timer (only fires while the tab is visible)\n * - the tab becoming visible again after `lastTokenRefresh` has gone stale\n *\n * Non-stamped tokens (e.g. personal access tokens) are never refreshed.\n *\n * @internal\n */\nexport const refreshStampedToken = ({\n state,\n instance,\n}: StoreContext<AuthStoreState>): Subscription => {\n const logger = getAuthLogger(instance)\n\n const {clientFactory, apiHost, storageArea, storageKey} = state.get().options\n\n const refreshToken$ = state.observable.pipe(\n map((storeState) => storeState.authState),\n filter(\n (authState): authState is Extract<AuthState, {type: AuthStateType.LOGGED_IN}> =>\n authState.type === AuthStateType.LOGGED_IN,\n ),\n distinctUntilChanged((prev, curr) => prev.token === curr.token),\n filter((authState) => authState.token.includes('-st')), // Ensure we only try to refresh stamped tokens\n exhaustMap(() =>\n new Observable<{token: string}>((subscriber) => {\n const visibilityHandler = () => {\n const currentState = state.get()\n if (\n document.visibilityState === 'visible' &&\n currentState.authState.type === AuthStateType.LOGGED_IN &&\n shouldRefreshToken(currentState.authState.lastTokenRefresh)\n ) {\n createTokenRefreshStream(\n currentState.authState.token,\n clientFactory,\n apiHost,\n ).subscribe({\n next: (response) => {\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {\n ...prev.authState,\n token: response.token,\n lastTokenRefresh: Date.now(),\n }\n : prev.authState,\n }))\n subscriber.next(response)\n },\n error: (error) => subscriber.error(error),\n })\n }\n }\n\n const timerSubscription = timer(REFRESH_INTERVAL, REFRESH_INTERVAL)\n .pipe(\n filter(() => document.visibilityState === 'visible'),\n switchMap(() => {\n const currentState = state.get().authState\n if (currentState.type !== AuthStateType.LOGGED_IN) {\n throw new Error('User logged out before refresh could complete')\n }\n return createTokenRefreshStream(currentState.token, clientFactory, apiHost)\n }),\n )\n .subscribe({\n next: (response) => {\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {\n ...prev.authState,\n token: response.token,\n lastTokenRefresh: Date.now(),\n }\n : prev.authState,\n }))\n subscriber.next(response)\n },\n error: (error) => subscriber.error(error),\n })\n\n document.addEventListener('visibilitychange', visibilityHandler)\n\n return () => {\n document.removeEventListener('visibilitychange', visibilityHandler)\n timerSubscription.unsubscribe()\n }\n }).pipe(\n takeWhile(() => state.get().authState.type === AuthStateType.LOGGED_IN),\n map((response: {token: string}) => ({token: response.token})),\n ),\n ),\n )\n\n return refreshToken$.subscribe({\n next: (response: {token: string}) => {\n logger.debug('Token refresh completed, updating state')\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {\n ...prev.authState,\n token: response.token,\n lastTokenRefresh: Date.now(),\n }\n : prev.authState,\n }))\n storageArea?.setItem(storageKey, JSON.stringify({token: response.token}))\n },\n error: (error) => {\n logger.error('Token refresh failed', {error})\n state.set('setRefreshStampedTokenError', {authState: {type: AuthStateType.ERROR, error}})\n },\n })\n}\n","import {type CurrentUser} from '@sanity/types'\nimport {\n catchError,\n distinctUntilChanged,\n EMPTY,\n filter,\n map,\n type Subscription,\n switchMap,\n} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'\nimport {getAuthLogger} from './authLogger'\nimport {isStudioConfig} from './authMode'\nimport {AuthStateType} from './authStateType'\nimport {type AuthMethodOptions, type AuthState, type AuthStoreState} from './authStore'\n\n/**\n * Subscribes to auth state changes and fetches the current user when\n * the state transitions to `LOGGED_IN` without a `currentUser`.\n *\n * @param context - The store context for the auth store.\n * @param fetchOptions - Configuration options. When `useProjectHostname` is\n * `true`, requests use the project-specific hostname (required for Studio\n * cookie auth). Set to `true` for studio mode, `false` otherwise.\n *\n * @internal\n */\nexport const subscribeToStateAndFetchCurrentUser = (\n {state, instance}: StoreContext<AuthStoreState>,\n fetchOptions?: {useProjectHostname?: boolean},\n): Subscription => {\n const logger = getAuthLogger(instance)\n\n const {clientFactory, apiHost} = state.get().options\n const useProjectHostname = fetchOptions?.useProjectHostname ?? isStudioConfig(instance.config)\n const projectId = instance.config.projectId\n\n const currentUser$ = state.observable\n .pipe(\n map(({authState, options: storeOptions}) => ({\n authState,\n authMethod: storeOptions.authMethod,\n })),\n filter(\n (\n value,\n ): value is {\n authState: Extract<AuthState, {type: AuthStateType.LOGGED_IN}>\n authMethod: AuthMethodOptions\n } => value.authState.type === AuthStateType.LOGGED_IN && !value.authState.currentUser,\n ),\n map((value) => ({token: value.authState.token, authMethod: value.authMethod})),\n distinctUntilChanged(\n (prev, curr) => prev.token === curr.token && prev.authMethod === curr.authMethod,\n ),\n )\n .pipe(\n map(({token, authMethod}) =>\n clientFactory({\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n token: authMethod === 'cookie' ? undefined : token,\n ignoreBrowserTokenWarning: true,\n useProjectHostname,\n useCdn: false,\n ...(authMethod === 'cookie' ? {withCredentials: true} : {}),\n ...(useProjectHostname && projectId ? {projectId} : {}),\n ...(apiHost && {apiHost}),\n }),\n ),\n switchMap((client) =>\n client.observable\n .request<CurrentUser>({\n url: '/users/me',\n method: 'GET',\n tag: 'users.get-current',\n })\n .pipe(\n /**\n * Catch inside switchMap so the outer subscription survives.\n * Without this, a 401 terminates the subscription permanently\n * and subsequent token refreshes via comlink never re-fetch /users/me.\n * @see SDK-1409\n */\n catchError((error) => {\n logger.error('Failed to fetch current user', {error})\n state.set('setError', {authState: {type: AuthStateType.ERROR, error}})\n return EMPTY\n }),\n ),\n ),\n )\n\n return currentUser$.subscribe({\n next: (currentUser) => {\n logger.info('Current user fetched successfully', {\n hasEmail: !!currentUser.email,\n })\n // userId is PII, so only surface it at debug level\n logger.debug('Current user details', {userId: currentUser.id})\n state.set('setCurrentUser', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {...prev.authState, currentUser}\n : prev.authState,\n }))\n },\n })\n}\n","import {type ClientError} from '@sanity/client'\nimport {type CurrentUser} from '@sanity/types'\nimport {EMPTY, fromEvent, Observable} from 'rxjs'\n\nimport {AUTH_CODE_PARAM, DEFAULT_BASE} from './authConstants'\nimport {AuthStateType} from './authStateType'\nimport {type LoggedInAuthState} from './authStore'\n\n/**\n * Creates a properly initialized {@link LoggedInAuthState}.\n *\n * For stamped tokens (containing `\"-st\"`), `lastTokenRefresh` is set to\n * `Date.now()` so that the visibility-change handler in\n * {@link refreshStampedToken} does not trigger an unnecessary refresh the\n * first time the tab becomes visible.\n *\n * @param token - The auth token.\n * @param currentUser - The current user, or `null` if not yet fetched.\n * @param existingLastTokenRefresh - An existing timestamp to preserve\n * (e.g. when updating a token while keeping the previous refresh time).\n * @internal\n */\nexport function createLoggedInAuthState(\n token: string,\n currentUser: CurrentUser | null,\n existingLastTokenRefresh?: number,\n): LoggedInAuthState {\n const isStampedToken = token.includes('-st')\n const lastTokenRefresh = existingLastTokenRefresh ?? (isStampedToken ? Date.now() : undefined)\n\n return {\n type: AuthStateType.LOGGED_IN,\n token,\n currentUser,\n ...(lastTokenRefresh !== undefined && {lastTokenRefresh}),\n }\n}\n\nexport function getAuthCode(callbackUrl: string | undefined, locationHref: string): string | null {\n const loc = new URL(locationHref, DEFAULT_BASE)\n const callbackLocation = callbackUrl ? new URL(callbackUrl, DEFAULT_BASE) : undefined\n const callbackLocationMatches = callbackLocation\n ? loc.pathname.toLowerCase().startsWith(callbackLocation.pathname.toLowerCase())\n : true\n\n // First, try getting the auth code (sid) from hash or search params directly\n let authCode =\n new URLSearchParams(loc.hash.slice(1)).get(AUTH_CODE_PARAM) ||\n new URLSearchParams(loc.search).get(AUTH_CODE_PARAM)\n\n // If not found directly, try extracting it from the _context parameter as a fallback\n if (!authCode) {\n const contextParam = new URLSearchParams(loc.search).get('_context')\n if (contextParam) {\n try {\n const parsedContext = JSON.parse(contextParam)\n if (\n parsedContext &&\n typeof parsedContext === 'object' &&\n typeof parsedContext.sid === 'string' &&\n parsedContext.sid // Ensure it's not an empty string\n ) {\n authCode = parsedContext.sid\n }\n } catch {\n // Silently ignore _context JSON parsing errors; authCode remains null/empty\n }\n }\n }\n\n return authCode && callbackLocationMatches ? authCode : null\n}\n\nexport function getTokenFromLocation(locationHref: string): string | null {\n const loc = new URL(locationHref)\n const token = new URLSearchParams(loc.hash.slice(1)).get('token')\n return token ? token : null\n}\n\n/**\n * Attempts to retrieve a token from the configured storage.\n * If invalid or not present, returns null.\n */\nexport function getTokenFromStorage(\n storageArea: Storage | undefined,\n storageKey: string,\n): string | null {\n if (!storageArea) return null\n const item = storageArea.getItem(storageKey)\n if (item === null) return null\n\n try {\n const parsed: unknown = JSON.parse(item)\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n !('token' in parsed) ||\n typeof parsed.token !== 'string'\n ) {\n throw new Error('Invalid stored auth data structure')\n }\n return parsed.token\n } catch {\n storageArea.removeItem(storageKey)\n return null\n }\n}\n\n/**\n * Creates an observable stream of storage events. If not in a browser environment,\n * returns an EMPTY observable.\n */\nexport function getStorageEvents(): Observable<StorageEvent> {\n const isBrowser = typeof window !== 'undefined' && typeof window.addEventListener === 'function'\n\n if (!isBrowser) {\n return EMPTY\n }\n\n return fromEvent<StorageEvent>(window, 'storage')\n}\n\n/**\n * Returns a default storage instance (localStorage) if available.\n * If not available or an error occurs, returns undefined.\n */\nexport function getDefaultStorage(): Storage | undefined {\n try {\n if (typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function') {\n return localStorage\n }\n return undefined\n } catch {\n return undefined\n }\n}\n\n/**\n * Returns the default location to use.\n * Tries accessing `location.href`, falls back to a default base if not available or on error.\n */\nexport function getDefaultLocation(): string {\n try {\n if (typeof location === 'undefined') return DEFAULT_BASE\n if (typeof location.href === 'string') return location.href\n return DEFAULT_BASE\n } catch {\n return DEFAULT_BASE\n }\n}\n\n/**\n * Cleans up the URL by removing the `token` from the hash and the `sid` and `url` search params.\n * @internal\n */\nexport function getCleanedUrl(locationUrl: string): string {\n const loc = new URL(locationUrl)\n // Remove only the `token` param from the hash while preserving other fragments\n const rawHash = loc.hash.startsWith('#') ? loc.hash.slice(1) : loc.hash\n if (rawHash && rawHash.includes('=')) {\n const hashParams = new URLSearchParams(rawHash)\n hashParams.delete('token')\n hashParams.delete('withSid')\n const nextHash = hashParams.toString()\n loc.hash = nextHash ? `#${nextHash}` : ''\n }\n loc.searchParams.delete('sid')\n loc.searchParams.delete('url')\n return loc.toString()\n}\n\n// -----------------------------------------------------------------------------\n// ClientError helpers (shared)\n// -----------------------------------------------------------------------------\n\n/** @internal */\nexport type ApiErrorBody = {\n error?: {type?: string; description?: string; projectID?: unknown; userID?: unknown}\n type?: string\n description?: string\n message?: string\n}\n\n/** @internal Extracts the structured API error body from a ClientError, if present. */\nexport function getClientErrorApiBody(error: ClientError): ApiErrorBody | undefined {\n const body: unknown = (error as ClientError).response?.body\n return body && typeof body === 'object' ? (body as ApiErrorBody) : undefined\n}\n\n/** @internal Returns the error type string from an API error body, if available. */\nexport function getClientErrorApiType(error: ClientError): string | undefined {\n const body = getClientErrorApiBody(error)\n return body?.error?.type ?? body?.type\n}\n\n/**\n * Returns the project an API error refers to, if available.\n * @internal\n */\nexport function getClientErrorApiProjectId(error: ClientError): string | undefined {\n const projectId = getClientErrorApiBody(error)?.error?.projectID\n return typeof projectId === 'string' && projectId ? projectId : undefined\n}\n","import {type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {DEFAULT_BASE} from './authConstants'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState, type DashboardContext} from './authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from './authStrategy'\nimport {refreshStampedToken} from './refreshStampedToken'\nimport {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'\nimport {createLoggedInAuthState, getAuthCode, getTokenFromLocation} from './utils'\n\n/**\n * Parses the dashboard context from a location href's `_context` URL parameter.\n * Strips the `sid` property from the parsed context (it's handled separately).\n *\n * @internal\n */\nfunction parseDashboardContext(locationHref: string): DashboardContext {\n try {\n const parsedUrl = new URL(locationHref, DEFAULT_BASE)\n const contextParam = parsedUrl.searchParams.get('_context')\n if (contextParam) {\n const parsedContext = JSON.parse(contextParam)\n\n if (\n parsedContext &&\n typeof parsedContext === 'object' &&\n !Array.isArray(parsedContext) &&\n Object.keys(parsedContext).length > 0\n ) {\n // Explicitly remove the 'sid' property before assigning\n delete parsedContext.sid\n return parsedContext as DashboardContext\n }\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('Failed to parse dashboard context from initial location:', err)\n }\n return {} // Empty dashboard context if parsing fails\n}\n\n/**\n * Resolves the initial auth state for Dashboard mode.\n *\n * In dashboard mode the token is provided by the parent frame via Comlink,\n * so the SDK starts in a `LOGGED_OUT` state and waits for the token to arrive.\n * The `_context` URL parameter provides dashboard metadata (orgId, mode, env).\n *\n * A provided token (`auth.token`) or an auth code/callback still takes\n * precedence, even when running inside the dashboard.\n *\n * @internal\n */\nexport function getDashboardInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, initialLocationHref} = options\n const providedToken = authConfig.token\n const callbackUrl = authConfig.callbackUrl\n const storageKey = '__sanity_auth_token'\n\n const dashboardContext = parseDashboardContext(initialLocationHref)\n\n // Dashboard does NOT use localStorage — token comes from the parent frame\n const storageArea = undefined\n\n // Provided token always wins, even in dashboard\n if (providedToken) {\n return {\n authState: createLoggedInAuthState(providedToken, null),\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext,\n }\n }\n\n // Check for auth code or token-from-location (callback handling)\n if (getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref)) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext,\n }\n }\n\n // Default: logged out, waiting for Comlink to provide token\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext,\n }\n}\n\n/**\n * Initialize Dashboard auth subscriptions:\n * - Subscribe to state changes and fetch current user\n * - Start stamped token refresh\n *\n * Note: storage events are NOT subscribed in dashboard mode since\n * the dashboard does not use localStorage for token persistence.\n *\n * @internal\n */\nexport function initializeDashboardAuth(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n let startedRefresher = false\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: false}))\n\n // Dashboard does not subscribe to storage events\n\n if (!tokenRefresherRunning) {\n startedRefresher = true\n subscriptions.push(refreshStampedToken(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: startedRefresher,\n }\n}\n","import {type SanityClient} from '@sanity/client'\n\nimport {REQUEST_TAG_PREFIX} from '../authConstants'\nimport {type AuthStoreState} from '../authStore'\nimport {type OAuthTokens} from './types'\n\n/** The token endpoint's JSON response shape. */\nexport interface TokenEndpointResponse {\n access_token: string\n token_type: string\n expires_in: number\n refresh_token?: string\n}\n\ntype AuthOptions = AuthStoreState['options']\n\n/** Auth store options narrowed to an instance configured for OAuth. */\nexport type ConfiguredOAuthOptions = AuthOptions & {oauth: NonNullable<AuthOptions['oauth']>}\n\n/** Builds the RFC 8707 resource indicator for an organisation. */\nfunction getResourceIndicator(organizationId: string): string {\n return `urn:io.sanity:organization:${organizationId}`\n}\n\n/**\n * Appends the RFC 8707 `resource` indicator to `params` when an organisation\n * id is configured. Without one, the request is left unscoped.\n */\nexport function appendResourceIndicator(\n params: URLSearchParams,\n oauth: ConfiguredOAuthOptions['oauth'],\n): void {\n if (oauth.organizationId) {\n params.append('resource', getResourceIndicator(oauth.organizationId))\n }\n}\n\n/**\n * Serialises tokens for storage, converting `expiresAt` to an ISO string.\n *\n * @internal\n */\nexport function serializeTokens(tokens: OAuthTokens): string {\n return JSON.stringify({\n accessToken: tokens.accessToken,\n tokenType: tokens.tokenType,\n expiresIn: tokens.expiresIn,\n expiresAt: tokens.expiresAt.toISOString(),\n ...(tokens.refreshToken !== undefined && {refreshToken: tokens.refreshToken}),\n })\n}\n\n/**\n * Reads the store options, throwing when the instance was not configured for\n * OAuth.\n */\nexport function getOAuthOptions(state: AuthStoreState): ConfiguredOAuthOptions {\n const {options} = state\n if (!options.oauth) {\n throw new Error('OAuth is not configured on this instance (missing `auth.oauth`).')\n }\n return options as ConfiguredOAuthOptions\n}\n\n/** Creates a client for the (unauthenticated) public OAuth token/revoke calls. */\nexport function createOAuthClient(options: AuthOptions): SanityClient {\n return options.clientFactory({\n apiVersion: 'v1',\n requestTagPrefix: REQUEST_TAG_PREFIX,\n useProjectHostname: false,\n useCdn: false,\n ...(options.apiHost && {apiHost: options.apiHost}),\n })\n}\n\n/** POSTs form-encoded params to the OAuth token endpoint. */\nexport function postTokenRequest(\n client: SanityClient,\n params: URLSearchParams,\n tag: string,\n): Promise<TokenEndpointResponse> {\n return client.request<TokenEndpointResponse>({\n method: 'POST',\n url: '/auth/oauth/token',\n headers: {'content-type': 'application/x-www-form-urlencoded'},\n body: params.toString(),\n tag,\n })\n}\n\n/** Converts a token endpoint response to the {@link OAuthTokens} shape. */\nexport function toOAuthTokens(response: TokenEndpointResponse): OAuthTokens {\n return {\n accessToken: response.access_token,\n tokenType: 'bearer',\n expiresIn: response.expires_in,\n expiresAt: new Date(Date.now() + response.expires_in * 1000),\n ...(response.refresh_token !== undefined && {refreshToken: response.refresh_token}),\n }\n}\n","import {ClientError} from '@sanity/client'\n\nimport {type StoreContext} from '../../store/defineStore'\nimport {getAuthLogger} from '../authLogger'\nimport {AuthStateType} from '../authStateType'\nimport {type AuthStoreState} from '../authStore'\nimport {createLoggedInAuthState} from '../utils'\nimport {\n appendResourceIndicator,\n createOAuthClient,\n getOAuthOptions,\n postTokenRequest,\n serializeTokens,\n toOAuthTokens,\n} from './oauthClient'\nimport {type OAuthTokens} from './types'\n\n/**\n * A refresh failure is unrecoverable only when the token endpoint rejects the\n * refresh token itself (a 4xx). Rate-limit (429) and request-timeout (408)\n * responses, 5xx errors and network failures are transient, so the session is\n * kept intact for the caller to retry rather than forcing a logout.\n */\nfunction isUnrecoverableRefreshError(error: unknown): boolean {\n return error instanceof ClientError && error.statusCode !== 408 && error.statusCode !== 429\n}\n\n// Single-flight refresh shared across concurrent callers. Safe as a module\n// singleton because `authStore` is a global store (one shared state).\n// ponytail: module-level single-flight; upgrade to per-store keying only if\n// the auth store ever stops being global.\nlet refreshInFlight: Promise<Omit<OAuthTokens, 'refreshToken'> | null> | null = null\n\n/**\n * Refreshes the OAuth tokens using the `refresh_token` grant. Concurrent\n * callers share a single in-flight request. An unrecoverable failure (a 4xx\n * rejecting the refresh token) clears the tokens and transitions to\n * `LOGGED_OUT`; transient failures (network, 5xx, rate limits) leave the\n * session intact and rethrow so the caller can retry. The resolved tokens omit\n * the refresh token, which core retains internally for subsequent refreshes.\n *\n * Lives outside `oauthActions` so the auth store's initialisation path can\n * call it without importing the bound actions (which import the store).\n *\n * @internal\n */\nexport function runOAuthTokenRefresh(\n context: StoreContext<AuthStoreState>,\n): Promise<Omit<OAuthTokens, 'refreshToken'> | null> {\n if (refreshInFlight) return refreshInFlight\n refreshInFlight = doRefreshOAuthTokens(context).finally(() => {\n refreshInFlight = null\n })\n return refreshInFlight\n}\n\nasync function doRefreshOAuthTokens({\n state,\n instance,\n}: StoreContext<AuthStoreState>): Promise<Omit<OAuthTokens, 'refreshToken'> | null> {\n const logger = getAuthLogger(instance)\n const options = getOAuthOptions(state.get())\n\n const current = state.get().oauthTokens\n if (!current?.refreshToken) {\n logger.warn('No refresh token available — logging out')\n options.storageArea?.removeItem(options.storageKey)\n state.set('oauthRefreshNoToken', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n oauthTokens: undefined,\n })\n return null\n }\n\n try {\n const client = createOAuthClient(options)\n const params = new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: current.refreshToken,\n client_id: options.oauth.clientId,\n })\n appendResourceIndicator(params, options.oauth)\n const response = await postTokenRequest(client, params, 'oauth.refresh')\n\n const tokens = toOAuthTokens(response)\n if (!tokens.refreshToken) tokens.refreshToken = current.refreshToken\n\n options.storageArea?.setItem(options.storageKey, serializeTokens(tokens))\n logger.info('OAuth tokens refreshed')\n state.set('oauthRefreshed', {\n authState: createLoggedInAuthState(tokens.accessToken, null),\n oauthTokens: tokens,\n })\n const {refreshToken: _refreshToken, ...publicTokens} = tokens\n return publicTokens\n } catch (error) {\n if (!isUnrecoverableRefreshError(error)) {\n // Transient (network / 5xx / rate limit) — keep the session so the\n // caller can retry instead of forcing a logout.\n logger.warn('OAuth token refresh failed — keeping session for retry', {error})\n throw error\n }\n logger.error('OAuth token refresh failed — logging out', {error})\n options.storageArea?.removeItem(options.storageKey)\n state.set('oauthRefreshFailed', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n oauthTokens: undefined,\n })\n throw error\n }\n}\n","import {defer, distinctUntilChanged, filter, map, type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../../store/defineStore'\nimport {DEFAULT_BASE} from '../authConstants'\nimport {AuthStateType} from '../authStateType'\nimport {type AuthStoreState} from '../authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from '../authStrategy'\nimport {subscribeToStateAndFetchCurrentUser} from '../subscribeToStateAndFetchCurrentUser'\nimport {createLoggedInAuthState, getDefaultStorage, getStorageEvents} from '../utils'\nimport {runOAuthTokenRefresh} from './oauthRefresh'\nimport {type OAuthTokens} from './types'\n\n/** localStorage (or configured `storageArea`) key for persisted OAuth tokens. */\nexport const OAUTH_TOKENS_KEY = '__sanity_oauth_tokens'\n\n/** The persisted JSON shape of {@link OAuthTokens}, `expiresAt` as an ISO string. */\ninterface SerializedOAuthTokens extends Omit<OAuthTokens, 'expiresAt'> {\n expiresAt: string\n}\n\n/**\n * Parses persisted token JSON back into {@link OAuthTokens}. Returns `null`\n * when the value is missing or malformed, including an `expiresAt` that does\n * not parse to a valid date (an `Invalid Date` would otherwise read as never\n * expiring, since `NaN <= now` is always `false`).\n *\n * @internal\n */\nexport function deserializeTokens(raw: string | null): OAuthTokens | null {\n if (!raw) return null\n try {\n const parsed: unknown = JSON.parse(raw)\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n !('accessToken' in parsed) ||\n typeof (parsed as SerializedOAuthTokens).accessToken !== 'string' ||\n !('expiresAt' in parsed) ||\n typeof (parsed as SerializedOAuthTokens).expiresAt !== 'string'\n ) {\n return null\n }\n const value = parsed as SerializedOAuthTokens\n const expiresAt = new Date(value.expiresAt)\n if (Number.isNaN(expiresAt.getTime())) return null\n return {\n accessToken: value.accessToken,\n tokenType: 'bearer',\n expiresIn: value.expiresIn,\n expiresAt,\n ...(value.refreshToken !== undefined && {refreshToken: value.refreshToken}),\n }\n } catch {\n return null\n }\n}\n\n/**\n * Reads the persisted tokens, discarding entries that can never lead to a\n * session: corrupt JSON, or an expired access token with no refresh token.\n * Dropping them from storage stops them shadowing a fresh login.\n */\nfunction readPersistedTokens(\n storageArea: Storage | undefined,\n): {tokens: OAuthTokens; expired: boolean} | null {\n const raw = storageArea?.getItem(OAUTH_TOKENS_KEY) ?? null\n const tokens = deserializeTokens(raw)\n const expired = tokens !== null && tokens.expiresAt.getTime() <= Date.now()\n if (tokens && (!expired || tokens.refreshToken)) return {tokens, expired}\n if (raw) storageArea?.removeItem(OAUTH_TOKENS_KEY)\n return null\n}\n\n/**\n * Resolves the initial auth state for OAuth mode.\n *\n * State discovery order:\n * 1. Persisted tokens in `__sanity_oauth_tokens` → `LOGGED_IN`, or\n * `LOGGING_IN` when the access token has expired but a refresh token is\n * available (`initializeOauthAuth` then refreshes). Corrupt or expired\n * tokens without a refresh token are discarded.\n * 2. Callback URL (contains `code` or `error` and matches `redirectUri`)\n * → `LOGGING_IN`\n * 3. Otherwise → `LOGGED_OUT`\n *\n * @internal\n */\nexport function getOauthInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, initialLocationHref} = options\n const storageKey = OAUTH_TOKENS_KEY\n const storageArea = authConfig.storageArea ?? getDefaultStorage()\n const redirectUri = authConfig.oauth?.redirectUri\n\n // Persisted tokens win\n const persisted = readPersistedTokens(storageArea)\n if (persisted) {\n const {tokens, expired} = persisted\n return {\n // An expired token is not usable yet; `isExchangingToken` also makes\n // handleOAuthCallback stand down until the refresh has settled.\n authState: expired\n ? {type: AuthStateType.LOGGING_IN, isExchangingToken: true}\n : createLoggedInAuthState(tokens.accessToken, null),\n storageKey,\n storageArea,\n authMethod: 'localstorage',\n dashboardContext: {},\n oauthTokens: tokens,\n }\n }\n\n // Callback URL with code/error whose origin + pathname match our redirect\n // URI (query and hash are ignored). `state` alone is not a callback: the\n // server always sends `code` or `error`, and handleOAuthCallback would\n // otherwise leave the app stuck in LOGGING_IN.\n const {searchParams} = new URL(initialLocationHref, DEFAULT_BASE)\n const isCallback = searchParams.has('code') || searchParams.has('error')\n if (redirectUri && isCallback) {\n const loc = new URL(initialLocationHref, DEFAULT_BASE)\n const redirect = new URL(redirectUri, DEFAULT_BASE)\n if (loc.origin === redirect.origin && loc.pathname === redirect.pathname) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n }\n\n // No tokens, not a callback\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n}\n\n/**\n * Subscribes to cross-tab `storage` events for the OAuth tokens key, syncing\n * this tab's auth state when tokens change in another tab.\n *\n * @internal\n */\nexport function subscribeToOAuthStorageEvents({state}: StoreContext<AuthStoreState>): Subscription {\n const {storageArea} = state.get().options\n\n const tokens$ = defer(getStorageEvents).pipe(\n filter((e) => e.storageArea === storageArea && e.key === OAUTH_TOKENS_KEY),\n map(() => deserializeTokens(storageArea?.getItem(OAUTH_TOKENS_KEY) ?? null)),\n distinctUntilChanged((a, b) => a?.accessToken === b?.accessToken),\n )\n\n return tokens$.subscribe((tokens) => {\n state.set('updateOAuthTokensFromStorageEvent', {\n authState: tokens\n ? createLoggedInAuthState(tokens.accessToken, null)\n : {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n oauthTokens: tokens ?? undefined,\n })\n })\n}\n\n/**\n * Initialize OAuth auth subscriptions:\n * - Refresh persisted tokens that expired while the app was closed\n * - Subscribe to state changes and fetch current user\n * - Subscribe to cross-tab storage events for the OAuth tokens key\n *\n * OAuth tokens are refreshed via the `refresh_token` grant (see\n * `refreshOAuthTokens`), so the stamped-token refresher is not started here.\n *\n * @internal\n */\nexport function initializeOauthAuth(context: StoreContext<AuthStoreState>): {\n dispose: () => void\n tokenRefresherStarted: boolean\n} {\n const subscriptions: Subscription[] = []\n\n const {authState, oauthTokens, options} = context.state.get()\n if (authState.type === AuthStateType.LOGGING_IN && oauthTokens) {\n // getOauthInitialState handed us expired tokens with a refresh token.\n // Unrecoverable failures already end in LOGGED_OUT; a transient one is\n // surfaced rather than leaving the app stuck in LOGGING_IN.\n runOAuthTokenRefresh(context).catch((error) => {\n context.state.set('oauthStartupRefreshError', {\n authState: {type: AuthStateType.ERROR, error},\n })\n })\n }\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: false}))\n\n const storageArea = options?.storageArea\n if (storageArea) {\n subscriptions.push(subscribeToOAuthStorageEvents(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: false,\n }\n}\n","import {defer, distinctUntilChanged, filter, map, type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState} from './authStore'\nimport {createLoggedInAuthState, getStorageEvents, getTokenFromStorage} from './utils'\n\nexport const subscribeToStorageEventsAndSetToken = ({\n state,\n}: StoreContext<AuthStoreState>): Subscription => {\n const {storageArea, storageKey} = state.get().options\n\n const tokenFromStorage$ = defer(getStorageEvents).pipe(\n filter(\n (e): e is StorageEvent & {newValue: string} =>\n e.storageArea === storageArea && e.key === storageKey,\n ),\n map(() => getTokenFromStorage(storageArea, storageKey)),\n distinctUntilChanged(),\n )\n\n return tokenFromStorage$.subscribe((token) => {\n state.set('updateTokenFromStorageEvent', {\n authState: token\n ? createLoggedInAuthState(token, null)\n : {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n })\n })\n}\n","import {type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState} from './authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from './authStrategy'\nimport {refreshStampedToken} from './refreshStampedToken'\nimport {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'\nimport {subscribeToStorageEventsAndSetToken} from './subscribeToStorageEventsAndSetToken'\nimport {\n createLoggedInAuthState,\n getAuthCode,\n getDefaultStorage,\n getTokenFromLocation,\n getTokenFromStorage,\n} from './utils'\n\n/**\n * Resolves the initial auth state for Standalone mode.\n *\n * Token discovery order:\n * 1. Provided token (`auth.token` in config)\n * 2. Auth code or token from location (OAuth callback)\n * 3. localStorage: `__sanity_auth_token`\n * 4. Falls back to `LOGGED_OUT`\n *\n * @internal\n */\nexport function getStandaloneInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, initialLocationHref} = options\n const providedToken = authConfig.token\n const callbackUrl = authConfig.callbackUrl\n const storageKey = '__sanity_auth_token'\n const storageArea = authConfig.storageArea ?? getDefaultStorage()\n\n // Provided token always wins\n if (providedToken) {\n return {\n authState: createLoggedInAuthState(providedToken, null),\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n\n // Check for auth code or token-from-location (OAuth callback)\n if (getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref)) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n\n // Try localStorage\n const token = getTokenFromStorage(storageArea, storageKey)\n if (token) {\n return {\n authState: createLoggedInAuthState(token, null),\n storageKey,\n storageArea,\n authMethod: 'localstorage',\n dashboardContext: {},\n }\n }\n\n // No token found\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n}\n\n/**\n * Initialize Standalone auth subscriptions:\n * - Subscribe to state changes and fetch current user\n * - Subscribe to storage events for token key\n * - Start stamped token refresh\n *\n * @internal\n */\nexport function initializeStandaloneAuth(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n let startedRefresher = false\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: false}))\n\n const storageArea = context.state.get().options?.storageArea\n if (storageArea) {\n subscriptions.push(subscribeToStorageEventsAndSetToken(context))\n }\n\n if (!tokenRefresherRunning) {\n startedRefresher = true\n subscriptions.push(refreshStampedToken(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: startedRefresher,\n }\n}\n","import {type ClientConfig, type SanityClient} from '@sanity/client'\n\nimport {REQUEST_TAG_PREFIX} from './authConstants'\nimport {getTokenFromStorage} from './utils'\n\n/**\n * Cookie auth is a best-effort probe — if the API doesn't respond quickly,\n * the user likely isn't cookie-authenticated and we should move on rather\n * than block the auth flow indefinitely.\n */\nconst COOKIE_AUTH_TIMEOUT_MS = 10_000\n\n/**\n * Attempts to check for cookie auth by making a withCredentials request to the users endpoint.\n * @param projectId - The project ID to check for cookie auth.\n * @param clientFactory - A factory function that creates a Sanity client.\n * @returns True if the user is authenticated, false otherwise.\n * @internal\n */\nexport async function checkForCookieAuth(\n projectId: string | undefined,\n clientFactory: (config: ClientConfig) => SanityClient,\n): Promise<boolean> {\n if (!projectId) return false\n try {\n const client = clientFactory({\n projectId,\n useCdn: false,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n timeout: COOKIE_AUTH_TIMEOUT_MS,\n })\n const user = await client.request({\n url: '/users/me',\n withCredentials: true,\n tag: 'users.get-current',\n })\n return user != null && typeof user === 'object' && typeof user.id === 'string'\n } catch {\n return false\n }\n}\n\n/**\n * Attempts to retrieve a studio token from local storage.\n * @param storageArea - The storage area to retrieve the token from.\n * @param storageKey - The storage key to retrieve the token from.\n * @returns The studio token or null if it does not exist.\n * @internal\n */\nexport function getStudioTokenFromLocalStorage(\n storageArea: Storage | undefined,\n storageKey: string | undefined,\n): string | null {\n if (!storageArea || !storageKey) return null\n const token = getTokenFromStorage(storageArea, storageKey)\n if (token) {\n return token\n }\n return null\n}\n","import {type Subscription} from 'rxjs'\n\nimport {type TokenSource} from '../config/sanityConfig'\nimport {type StoreContext} from '../store/defineStore'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState, type LoggedInAuthState} from './authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from './authStrategy'\nimport {refreshStampedToken} from './refreshStampedToken'\nimport {checkForCookieAuth, getStudioTokenFromLocalStorage} from './studioModeAuth'\nimport {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'\nimport {subscribeToStorageEventsAndSetToken} from './subscribeToStorageEventsAndSetToken'\nimport {createLoggedInAuthState, getDefaultStorage} from './utils'\n\n/**\n * Resolves the initial auth state for Studio mode.\n *\n * When a `tokenSource` is provided (via `config.studio.auth.token`), the\n * initial state is `LOGGING_IN` — the actual token arrives asynchronously\n * via the subscription set up in `initializeStudioAuth`.\n *\n * Fallback token discovery order (no tokenSource):\n * 1. Provided token (`auth.token` in config)\n * 2. localStorage: `__studio_auth_token_${projectId}`\n * 3. Falls back to `LOGGED_OUT` (cookie auth is checked async in `initializeStudioAuth`)\n *\n * @internal\n */\nexport function getStudioInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, projectId, tokenSource} = options\n const storageArea = authConfig.storageArea ?? getDefaultStorage()\n const studioStorageKey = `__studio_auth_token_${projectId ?? ''}`\n\n // When a reactive token source is available, start in LOGGING_IN state.\n // The actual token will arrive via subscription in initializeStudioAuth.\n if (tokenSource) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey: studioStorageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n\n // Fallback: discover token from config or localStorage\n const providedToken = authConfig.token\n\n // Check localStorage first — mirrors original authStore behavior where\n // the localStorage read always runs before the providedToken check.\n let authMethod: AuthStrategyResult['authMethod'] = undefined\n const token = getStudioTokenFromLocalStorage(storageArea, studioStorageKey)\n if (token) {\n authMethod = 'localstorage'\n }\n\n if (providedToken) {\n return {\n authState: createLoggedInAuthState(providedToken, null),\n storageKey: studioStorageKey,\n storageArea,\n authMethod,\n dashboardContext: {},\n }\n }\n\n if (token) {\n return {\n authState: createLoggedInAuthState(token, null),\n storageKey: studioStorageKey,\n storageArea,\n authMethod: 'localstorage',\n dashboardContext: {},\n }\n }\n\n // No token found — start logged out, cookie auth will be checked asynchronously\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey: studioStorageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n}\n\n/**\n * Initialize Studio auth subscriptions.\n *\n * When a `tokenSource` is available (reactive path), subscribes to it for\n * ongoing token sync. The Studio is the token authority — no independent\n * token refresh or cookie auth probing is needed.\n *\n * Fallback path (no tokenSource):\n * - Subscribe to state changes and fetch current user\n * - Subscribe to storage events for studio token key\n * - Check for cookie auth asynchronously if no token was found\n * - Start stamped token refresh\n *\n * @internal\n */\nexport function initializeStudioAuth(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const tokenSource = context.instance.config.studio?.auth?.token\n\n // Reactive token path — Studio provides the token\n if (tokenSource) {\n return initializeWithTokenSource(context, tokenSource)\n }\n\n // Fallback path — discover token from localStorage/cookies\n return initializeWithFallback(context, tokenRefresherRunning)\n}\n\n/**\n * Subscribe to a reactive token source from the Studio workspace.\n *\n * When the token source emits a non-null token, the SDK uses it directly.\n * When it emits `null`, the behavior depends on the `authenticated` flag\n * from the Studio's workspace config:\n *\n * - `authenticated: true` — the Studio has already verified the user is\n * logged in (e.g. via cookie auth). The SDK treats the null token as\n * cookie-based auth and stays in the LOGGED_IN state.\n *\n * - `authenticated` absent/false — the user is genuinely not authenticated;\n * transition to LOGGED_OUT.\n *\n * No async cookie probing is needed here because this code path only runs\n * when a Studio provides SDKStudioContext, and the Studio's Workspace type\n * always includes `authenticated`. The async `checkForCookieAuth` fallback\n * remains in `initializeWithFallback` for the non-Studio path.\n */\nfunction initializeWithTokenSource(\n context: StoreContext<AuthStoreState>,\n tokenSource: TokenSource,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n const studioAuthenticated = context.instance.config.studio?.authenticated === true\n\n // Subscribe to the current user fetcher — runs whenever auth state changes\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: true}))\n\n // Subscribe to the Studio's token stream\n const tokenSub = tokenSource.subscribe({\n next: (token) => {\n const {state} = context\n if (token) {\n // Studio provided a real token — use it directly\n state.set('studioTokenSource', (prev) => ({\n options: {...prev.options, authMethod: undefined},\n authState: createLoggedInAuthState(token, null),\n }))\n } else if (studioAuthenticated) {\n // The Studio says the user is authenticated — null token means\n // cookie-based auth is in use. Stay logged in with cookie method.\n state.set('studioTokenSourceCookieAuth', (prev) => ({\n options: {...prev.options, authMethod: 'cookie'},\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? prev.authState\n : createLoggedInAuthState('', null),\n }))\n } else {\n // No token and Studio doesn't confirm authentication — logged out\n state.set('studioTokenSourceLoggedOut', (prev) => ({\n options: {...prev.options, authMethod: undefined},\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n }))\n }\n },\n })\n\n return {\n dispose: () => {\n tokenSub.unsubscribe()\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n // Studio handles token refresh — do not start the SDK's refresher\n tokenRefresherStarted: false,\n }\n}\n\n/**\n * Fallback initialization when no reactive token source is available.\n * Uses localStorage/cookie discovery (existing behavior).\n */\nfunction initializeWithFallback(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n let startedRefresher = false\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: true}))\n\n const storageArea = context.state.get().options?.storageArea\n if (storageArea) {\n subscriptions.push(subscribeToStorageEventsAndSetToken(context))\n }\n\n // If no token found during getInitialState, try cookie auth asynchronously\n try {\n const {instance, state} = context\n const token: string | null =\n state.get().authState?.type === AuthStateType.LOGGED_IN\n ? (state.get().authState as LoggedInAuthState).token\n : null\n\n if (!token) {\n const projectIdValue = instance.config.projectId\n const clientFactory = state.get().options.clientFactory\n checkForCookieAuth(projectIdValue, clientFactory).then((isCookieAuthEnabled) => {\n if (!isCookieAuthEnabled) return\n state.set('enableCookieAuth', (prev) => ({\n options: {...prev.options, authMethod: 'cookie'},\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? prev.authState\n : createLoggedInAuthState('', null),\n }))\n })\n }\n } catch {\n // best-effort cookie detection\n }\n\n if (!tokenRefresherRunning) {\n startedRefresher = true\n subscriptions.push(refreshStampedToken(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: startedRefresher,\n }\n}\n","import {type ClientConfig, createClient, type SanityClient} from '@sanity/client'\nimport {type CurrentUser} from '@sanity/types'\n\nimport {type AuthConfig, type AuthProvider} from '../config/authConfig'\nimport {bindActionGlobally} from '../store/createActionBinder'\nimport {createStateSourceAction} from '../store/createStateSourceAction'\nimport {defineStore} from '../store/defineStore'\nimport {getStagingApiHost} from '../utils/getStagingApiHost'\nimport {getAuthLogger} from './authLogger'\nimport {resolveAuthMode} from './authMode'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStrategyOptions} from './authStrategy'\nimport {getDashboardInitialState, initializeDashboardAuth} from './dashboardAuth'\nimport {getOauthInitialState, initializeOauthAuth} from './oauth/oauthAuth'\nimport {type OAuthTokens} from './oauth/types'\nimport {getStandaloneInitialState, initializeStandaloneAuth} from './standaloneAuth'\nimport {getStudioInitialState, initializeStudioAuth} from './studioAuth'\nimport {createLoggedInAuthState, getCleanedUrl, getDefaultLocation} from './utils'\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Represents the various states the authentication can be in.\n *\n * @public\n */\nexport type AuthState = LoggedInAuthState | LoggedOutAuthState | LoggingInAuthState | ErrorAuthState\n\n/**\n * Logged-in state from the auth state.\n * @public\n */\nexport type LoggedInAuthState = {\n type: AuthStateType.LOGGED_IN\n token: string\n currentUser: CurrentUser | null\n lastTokenRefresh?: number\n}\n\n/**\n * Logged-out state from the auth state.\n * @public\n */\nexport type LoggedOutAuthState = {type: AuthStateType.LOGGED_OUT; isDestroyingSession: boolean}\n\n/**\n * Logging-in state from the auth state.\n * @public\n */\nexport type LoggingInAuthState = {type: AuthStateType.LOGGING_IN; isExchangingToken: boolean}\n\n/**\n * Error state from the auth state.\n * @public\n */\nexport type ErrorAuthState = {type: AuthStateType.ERROR; error: unknown}\n\n/**\n * Represents the various states the authentication can be in.\n *\n * @public\n */\nexport interface DashboardContext {\n mode?: string\n env?: string\n orgId?: string\n}\n\n/**\n * The method of authentication used.\n * @internal\n */\nexport type AuthMethodOptions = 'localstorage' | 'cookie' | undefined\n\nlet tokenRefresherRunning = false\n\n/**\n * @public\n */\nexport interface AuthStoreState {\n authState: AuthState\n providers?: AuthProvider[]\n options: {\n initialLocationHref: string\n clientFactory: (config: ClientConfig) => SanityClient\n customProviders: AuthConfig['providers']\n storageKey: string\n storageArea: Storage | undefined\n apiHost: string | undefined\n loginUrl: string\n callbackUrl: string | undefined\n providedToken: string | undefined\n authMethod: AuthMethodOptions\n oauth: AuthConfig['oauth']\n }\n dashboardContext?: DashboardContext\n oauthTokens?: OAuthTokens\n}\n\n// ---------------------------------------------------------------------------\n// Store definition — thin orchestrator\n// ---------------------------------------------------------------------------\n\nexport const authStore = defineStore<AuthStoreState>({\n name: 'Auth',\n\n getInitialState(instance) {\n const logger = getAuthLogger(instance)\n\n logger.debug('Initializing auth store', {\n hasProvidedToken: !!instance.config.auth?.token,\n hasCustomProviders: !!(\n instance.config.auth?.providers && instance.config.auth.providers.length > 0\n ),\n })\n\n const {\n apiHost: configApiHost,\n callbackUrl,\n providers: customProviders,\n token: providedToken,\n clientFactory = createClient,\n initialLocationHref = getDefaultLocation(),\n } = instance.config.auth ?? {}\n\n const apiHost = configApiHost ?? getStagingApiHost()\n const authConfig = instance.config.auth ?? {}\n\n // Build login URL (used by standalone mode, but always computed for the\n // public `getLoginUrlState` accessor)\n let loginDomain = 'https://www.sanity.io'\n try {\n if (apiHost && new URL(apiHost).hostname.endsWith('.sanity.work')) {\n loginDomain = 'https://www.sanity.work'\n }\n } catch {\n /* empty */\n }\n const loginUrl = new URL('/login', loginDomain)\n loginUrl.searchParams.set('origin', getCleanedUrl(initialLocationHref))\n loginUrl.searchParams.set('type', 'stampedToken') // Token must be stamped to have an sid passed back\n loginUrl.searchParams.set('withSid', 'true')\n\n // Resolve auth mode and delegate to the appropriate strategy\n const mode = resolveAuthMode(instance.config, initialLocationHref)\n\n const strategyOptions: AuthStrategyOptions = {\n authConfig,\n projectId: instance.config.projectId,\n initialLocationHref,\n clientFactory,\n tokenSource: instance.config.studio?.auth?.token,\n }\n\n let result\n switch (mode) {\n case 'studio':\n result = getStudioInitialState(strategyOptions)\n break\n case 'oauth':\n result = getOauthInitialState(strategyOptions)\n break\n case 'dashboard':\n result = getDashboardInitialState(strategyOptions)\n break\n case 'standalone':\n result = getStandaloneInitialState(strategyOptions)\n break\n }\n\n logger.debug('Auth state initialized', {\n authStateType: result.authState.type,\n mode,\n authMethod: result.authMethod,\n })\n\n return {\n authState: result.authState,\n dashboardContext: result.dashboardContext,\n oauthTokens: result.oauthTokens,\n options: {\n apiHost,\n loginUrl: loginUrl.toString(),\n callbackUrl,\n customProviders,\n providedToken,\n clientFactory,\n initialLocationHref,\n storageKey: result.storageKey,\n storageArea: result.storageArea,\n authMethod: result.authMethod,\n // Only expose oauth options when the oauth strategy is actually in use,\n // so mode-gated actions (logout, handleAuthCallback) stay consistent\n // with the resolved mode (e.g. `studio` takes precedence over `oauth`).\n oauth: mode === 'oauth' ? authConfig.oauth : undefined,\n },\n }\n },\n\n initialize(context) {\n const logger = getAuthLogger(context.instance)\n\n const initialLocationHref =\n context.state.get().options?.initialLocationHref ?? getDefaultLocation()\n const mode = resolveAuthMode(context.instance.config, initialLocationHref)\n\n logger.debug('Setting up auth subscriptions', {mode})\n\n let initResult\n switch (mode) {\n case 'studio':\n initResult = initializeStudioAuth(context, tokenRefresherRunning)\n break\n case 'oauth':\n initResult = initializeOauthAuth(context)\n break\n case 'dashboard':\n initResult = initializeDashboardAuth(context, tokenRefresherRunning)\n break\n case 'standalone':\n initResult = initializeStandaloneAuth(context, tokenRefresherRunning)\n break\n }\n\n if (initResult.tokenRefresherStarted) {\n tokenRefresherRunning = true\n }\n\n return () => {\n logger.debug('Cleaning up auth subscriptions')\n initResult.dispose()\n }\n },\n})\n\n// ---------------------------------------------------------------------------\n// Public bound actions\n// ---------------------------------------------------------------------------\n\n/**\n * @public\n */\nexport const getCurrentUserState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {authState}}) =>\n authState.type === AuthStateType.LOGGED_IN ? authState.currentUser : null,\n ),\n)\n\n/**\n * @public\n */\nexport const getTokenState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {authState}}) =>\n authState.type === AuthStateType.LOGGED_IN ? authState.token : null,\n ),\n)\n\n/**\n * @internal\n */\nexport const getAuthMethodState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {options}}) => options.authMethod),\n)\n\n/**\n * @public\n */\nexport const getLoginUrlState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {options}}) => options.loginUrl),\n)\n\n/**\n * @public\n */\nexport const getAuthState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {authState}}) => authState),\n)\n\n/**\n * Returns a state source indicating if the SDK is running within a dashboard context.\n * @public\n */\nexport const getIsInDashboardState = bindActionGlobally(\n authStore,\n createStateSourceAction(\n ({state: {dashboardContext}}) =>\n // Check if dashboardContext exists and is not empty\n !!dashboardContext && Object.keys(dashboardContext).length > 0,\n ),\n)\n\n/**\n * Action to explicitly set the authentication token.\n * Used internally by the Comlink token refresh.\n * @internal\n */\nexport const setAuthToken = bindActionGlobally(\n authStore,\n ({state, instance}, token: string | null) => {\n const logger = getAuthLogger(instance)\n\n const currentAuthState = state.get().authState\n if (token) {\n // Update state only if the new token is different or currently logged out\n if (currentAuthState.type !== AuthStateType.LOGGED_IN || currentAuthState.token !== token) {\n logger.info('Setting auth token')\n const currentUser =\n currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.currentUser : null\n const preservedLastTokenRefresh =\n currentAuthState.type === AuthStateType.LOGGED_IN\n ? currentAuthState.lastTokenRefresh\n : undefined\n state.set('setToken', {\n authState: createLoggedInAuthState(token, currentUser, preservedLastTokenRefresh),\n })\n }\n } else {\n // Handle setting token to null (logging out)\n if (currentAuthState.type !== AuthStateType.LOGGED_OUT) {\n logger.info('Clearing auth token')\n state.set('setToken', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n })\n }\n }\n },\n)\n"],"mappings":"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"}