import { A as CoreApp, D as Studio, V as RemoteModule, t as Application$1 } from "./application-list-Dh3Y9exX.js"; import { Observable } from "rxjs"; import { CurrentUser, OrganizationBase } from "@sanity/sdk"; type ColorScheme = "light" | "dark"; type ColorSchemePreference = "system" | ColorScheme; /** * The system-preferences machine's context. Consumers read fields directly * (e.g. via `useSelector`) rather than going through a resolver utility — * the action handlers keep `colorScheme` in sync with `preferredColorScheme` * and `osColorScheme`. * * Note: `colorScheme` is intentionally stored as derived state in context so * consumers can read the resolved value directly without a utility. The * action handlers below are the single source of truth for the resolution. * @public */ type SystemPreferencesContext = { /** User's color scheme choice; `system` defers to the OS preference. */ preferredColorScheme: ColorSchemePreference; /** Last reported OS color scheme. Used to resolve `colorScheme` when the * preference is `system`. */ osColorScheme: ColorScheme; /** Resolved color scheme — what the UI should render. Recomputed by the * action handlers whenever an input changes. */ colorScheme: ColorScheme; /** Whether the dock sidebar is pinned open. A plain stored boolean — * unlike `colorScheme` there is nothing to resolve. Defaults to locked. */ dockLocked: boolean; }; /** * Events the system-preferences machine accepts. All originate from the * host's adapter — `preferredColorScheme.set` and `dockLocked.set` are also * forwarded back to it so it can persist the user's choice. * @public */ type SystemPreferencesEvent = { type: "preferredColorScheme.set"; preferredColorScheme: ColorSchemePreference; } | { type: "osColorScheme.set"; osColorScheme: ColorScheme; } | { type: "dockLocked.set"; dockLocked: boolean; }; /** * Adapter interface the host implements to give the system-preferences * machine access to the user's environment (OS color scheme, persistent * storage, cross-context change notifications). * * The package owns all orchestration — synchronous seeding, idempotent * persistence, mapping cleared storage to `"system"`. The host's * implementation is pure DOM/storage glue: read, write, subscribe. * @public */ type SystemPreferencesAdapter = { /** Read the user's stored preference. `null` means "no preference set" * (the machine treats this as `"system"`). */ getPreferredColorScheme: () => ColorSchemePreference | null; /** Write the user's preference to persistent storage. */ persistPreferredColorScheme: (value: ColorSchemePreference) => void; /** Subscribe to cross-context preference changes (e.g. another tab * writing to the shared storage). The callback receives the new stored * value (or `null` if it was cleared). Returns an unsubscribe function. */ subscribePreferredColorScheme: (callback: (next: ColorSchemePreference | null) => void) => () => void; /** Read the current OS-detected color scheme. */ getOsColorScheme: () => ColorScheme; /** Subscribe to OS color-scheme changes (e.g. user flipping dark mode). * Returns an unsubscribe function. */ subscribeOsColorScheme: (callback: (next: ColorScheme) => void) => () => void; /** Read the user's stored dock-locked preference. `null` means "no * preference set" (the machine treats this as the default, locked). */ getDockLocked: () => boolean | null; /** Write the user's dock-locked preference to persistent storage. */ persistDockLocked: (value: boolean) => void; /** Subscribe to cross-context dock-locked changes (e.g. another tab writing * to the shared storage). The callback receives the new stored value (or * `null` if it was cleared). Returns an unsubscribe function. */ subscribeDockLocked: (callback: (next: boolean | null) => void) => () => void; }; /** @public */ type Application = Studio | CoreApp; /** * Declares a state topic: holds a current value, replayed to new subscribers. * @public */ type StateTopicDef = { kind: "state"; value: T; }; /** * Declares an event topic: a stream of occurrences with no memory. Declaring a * `reply` makes it a request topic — an awaited `emit` resolves with that reply. * @public */ type EventTopicDef = { kind: "event"; payload: P; reply?: R; }; /** * The value of a state topic that can fail independently of the session. One * `ok` discriminant across all such topics, so consumers can share failure * handling (e.g. a retry utility) without per-topic shapes. * @public */ type TopicResult = { ok: true; value: T; } | { ok: false; }; /** * A place in the workbench: an application plus a route inside it, never a shell * URL — the shape has to survive a router swap. `appId` is `null` on * workbench-level pages (home, account) and on any path no application claims, * an unresolved app route included. `path` carries the query string and * fragment; app-internal it has no leading slash, a workbench-level one keeps it. * @public */ type NavigationTarget = { appId: Application$1["id"] | null; path: string; }; /** * Where the workbench is, plus the navigation in flight. Mirrors the Navigation * API's `navigation.transition`, minus its `from` — that is this value. * @public */ type NavigationLocation = NavigationTarget & { transition: { navigationType: "push" | "replace"; to: NavigationTarget; } | null; }; /** * The topics the workbench itself owns. Every topic lands here with its owner's * publish wiring and, if bridge-bound, a clonability assertion in * `topics.test.ts`. A session-derived value must not outlive the session: such * topics clear (publish `null`) when the user signs out. * @public */ interface WorkbenchTopics { "applications.foreground": StateTopicDef; "applications.list": StateTopicDef | null>; /** * The session token the requesting app reads; `null` while signed out. Each * connection carries its app id, so per-app tokens can land later without * changing the contract — today every app reads the same session token. * Read-only for apps: published by the auth machine, cleared to `null` on * sign-out. Suspends until auth settles. */ "auth.token": StateTopicDef; /** * Requests the session token on demand, for an app that wants to re-fetch * rather than wait on its `auth.token` subscription (e.g. after a rejected * request). Carries the caller's app id. Today it resends the session's * current token — the seam where per-app re-issuance lands later. Fails * `NO_RESPONDER` while signed out. */ "auth.token.refresh": EventTopicDef; /** * The media library's deployment configuration, as a {@link RemoteModule} * to its config federation module. */ "media-libraries.config": StateTopicDef; /** * Where the workbench is, and what navigation is in flight; `null` once the * session ends. Unlike `applications.foreground`, this publishes on in-app * navigation too. Suspends until the first publish; published by the * navigation machine. */ "navigation.location": StateTopicDef; /** * Requests navigation, replying once it commits — the URL has changed and * `navigation.location` carries where the user landed. Requesting the * current location replies `ok` without navigating. Accepts relative and * same-origin absolute URLs; `history` defaults to `push`. * * `ok: false` reasons: * - `not-navigable` — off-origin, a URL that does not parse, a panel-only app, or a path a deployed core app's route cannot carry * - `interrupted` — superseded by a newer request, or the user navigated elsewhere, before it committed * - `failed` — the router refused the href, or never committed within 10s, which * only a caller waiting longer than the default 5s `emit` timeout ever reads * * Fails `NO_RESPONDER` while signed out. Responded to by the navigation machine. */ "navigation.location.update": EventTopicDef<{ url: string; history?: "push" | "replace"; }, { ok: true; } | { ok: false; reason: "not-navigable" | "interrupted" | "failed"; }>; /** * The session's organization context; `null` when signed out or the fetch * failed. Everything else is fetched against it. The bridgeable projection of * the SDK's `OrganizationBase`. Suspends until the first value arrives; * published by the organization machine, which keeps it in step with the * organization store for as long as the session is open. */ "organizations.current": StateTopicDef | null>; /** * The open panel — its owning app, the panel view's name, and its mode. Only * `aside` carries a width (px); `full` overlays the main area, so a width is * meaningless there. `value: null` when closed, `null` once the session ends. * Width is remembered per app + panel name across mode switches. Published by * the applications machine; apps write changes via `panels.mode.set`. */ "panels.mode": StateTopicDef | null>; /** * A change an app requests for its own panel: set its mode (opens it, or * switches aside/full), resize it without resending the mode, or `null` to * close. */ "panels.mode.set": EventTopicDef<{ name: string; mode: "aside" | "full"; } | { name: string; size: number; } | null>; /** * The resolved color scheme the workbench renders with — the user's * preference, falling back to the OS scheme. Environment-derived, not * session data: it stays published across sign-out (the login screen renders * with it too). Published synchronously at boot by the system-preferences * machine. */ "preferences.color-scheme": StateTopicDef; /** * Whether the dock sidebar is pinned open. Like `preferences.color-scheme`, * an environment-derived UI preference that stays published across sign-out. * Published synchronously at boot by the system-preferences machine. */ "preferences.dock-locked": StateTopicDef; /** * The signed-in user, or `null` when signed out. The bridgeable projection of * the SDK's `CurrentUser`. Suspends until auth settles; published by the auth * machine. */ "users.current": StateTopicDef | null>; } /** * The central topic registry — every call site is type-checked against it. * @public */ interface Topics extends WorkbenchTopics {} /** * Every declared topic name. * @public */ type TopicName = keyof Topics; type StateTopicsOf = { [K in keyof T]: T[K] extends { kind: "state"; } ? K : never; }[keyof T]; /** * Names of all declared state topics. * @public */ type StateTopic = StateTopicsOf; /** * Names of all declared event topics. * @public */ type EventTopic = { [K in TopicName]: Topics[K] extends { kind: "event"; } ? K : never; }[TopicName]; /** * The value type of a state topic. * @public */ type ValueOf = Topics[K] extends StateTopicDef ? T : never; /** * The payload type of an event topic. * @public */ type PayloadOf = Topics[K] extends EventTopicDef ? P : never; /** * The reply type of an event topic (`never` if it declares none). * @public */ type ReplyOf = Topics[K] extends EventTopicDef ? R : never; /** * One adjacent version step: `up` lifts the older shape, `down` projects back. * Request replies are not migrated — evolve them additively. * @internal */ interface TopicMigration { /** The older version this step lifts from / projects back to. */ readonly from: number; /** The newer version (`from + 1`). */ readonly to: number; up(older: unknown): unknown; down(newer: unknown): unknown; } /** * Message metadata. Reply routing is carried by the delivery mechanism, not the * envelope, so this is provenance only. * @public */ interface OsMeta { appId: string; timestamp: number; } /** * One envelope flowing through a topic. * @public */ interface Message { type: TopicName; payload: T; meta: OsMeta; } /** * What an event-topic handler receives: the envelope plus `reply` (routed back * to the awaiting caller) and `signal` (aborts when that caller stops waiting — * never on a fire-and-forget emit). * @public */ interface OsMessage extends Message { reply(value: R): void; readonly signal: AbortSignal; } /** * A state topic's read shape. Piping it drops `getCurrent` and `firstValue` (the * result is a plain `Observable`) — read them off the un-piped source. * @public */ interface StateSource extends Observable { getCurrent(): T | undefined; firstValue: Promise; } /** * The one teardown idiom: abort the `signal` to cancel a `query` or tear down a * `subscribe`. One controller scopes any number of them. * @public */ interface AbortOptions { signal?: AbortSignal; } /** * `emit` options. `timeout` (default 5s; `null` disables the deadline so the * `signal` governs) composes with the `signal` — whichever fires first rejects. * @public */ interface EmitOptions extends AbortOptions { timeout?: number | null; } /** * An event `emit`'s result. Awaiting it arms the failure machinery; not awaiting * is pure fire-and-forget. * @public */ interface EmitResult extends PromiseLike { catch(onRejected?: (reason: unknown) => T | PromiseLike): Promise; finally(onFinally?: () => void): Promise; } /** * The in-process message bus. State topics hold a current value (`query` / * `subscribe`); event topics stream occurrences, and a request topic (one that * declares a reply) resolves an awaited `emit` with that reply. * @public */ interface Bus { /** Publish a state topic's current value (fire-and-forget). */ emit(type: K, value: ValueOf): void; /** * Fire an event, or `await` it for a request topic's reply. A topic whose * payload is `void` takes no payload argument. */ emit(type: K, ...rest: PayloadOf extends void ? [payload?: void, options?: EmitOptions] : [payload: PayloadOf, options?: EmitOptions]): EmitResult>; /** * Read a state topic's value once. Seeded topics resolve at once; a suspending * one waits for its first value, bounded by the deadline and `signal` (rejects * `TIMEOUT`/`ABORTED`). */ query(type: K, options?: AbortOptions): Promise>; /** * Run `handler` for each event (it may `reply`). Tear down by aborting * `options.signal`; with none, it lives for the app's lifetime. */ subscribe(type: K, handler: (message: OsMessage, ReplyOf>) => void, options?: AbortOptions): void; /** React to a state topic's value; tears down when `options.signal` aborts. */ subscribe(type: K, handler: (value: ValueOf) => void, options?: AbortOptions): void; /** Compose a state topic as a `StateSource` (Observable + synchronous read). */ subscribe(type: K): StateSource>; /** Compose an event topic as an `Observable` of its payloads. */ subscribe(type: K): Observable>; } /** * Tear down everything an app holds on the bus in one abort. The next `connect` * for the same app id starts a fresh lifetime, so a reload replaces a * generation of handlers instead of stacking a new one. * @public */ declare function disconnectApp(bus: Bus, appId: string): void; /** * Options for {@link connect}. `appId` is stamped on every message the client * emits and scopes its lifetime (see {@link disconnectApp}); `migrations` pins * the client's per-topic versions and defaults to this copy's bundled chains. * @public */ interface ConnectOptions { appId?: string; migrations?: ReadonlyMap; } /** * Connect a client to the shared core: this copy's identity plus its topic * versions, recast per topic against the install in either direction (see * {@link topicAdapters}). * * The one connect-time failure is a core-protocol mismatch, which yields an * inert client rather than a throw here — `connect` runs at module evaluation, * where a throw would take the whole module graph down with it. * @public */ declare function connect(core: Bus, config?: ConnectOptions): Bus; /** * The client every remote and the host import: this copy's identity and topic * versions, connected to the shared core. * @public */ declare const os: Bus; /** * Registers state topics an app adds to `Topics`; `undefined` makes reads wait * for the first publish, and a name already used as an event topic throws. * @public */ declare function defineStateTopics(target: Bus, topics: Partial<{ [K in StateTopic]: ValueOf | undefined; }>): void; export { SystemPreferencesEvent as _, disconnectApp as a, NavigationLocation as c, ReplyOf as d, StateTopic as f, SystemPreferencesContext as g, SystemPreferencesAdapter as h, defineStateTopics as i, NavigationTarget as l, ValueOf as m, StateSource as n, os as o, TopicResult as p, connect as r, Application as s, ConnectOptions as t, PayloadOf as u }; //# sourceMappingURL=bus-CMwGmM1c.d.ts.map