@sanity/workbench 0.1.0-alpha.20 → 0.1.0-alpha.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks-es/module-federation.js +59 -0
- package/dist/_chunks-es/module-federation.js.map +1 -0
- package/dist/_chunks-es/studio.js +35 -7
- package/dist/_chunks-es/studio.js.map +1 -1
- package/dist/_internal.js +1 -2
- package/dist/_internal.js.map +1 -1
- package/dist/core.d.ts +168 -56
- package/dist/core.js +1 -2
- package/dist/core.js.map +1 -1
- package/dist/system.d.ts +16 -1
- package/dist/system.js +1 -2
- package/dist/system.js.map +1 -1
- package/package.json +6 -5
- package/src/_internal/render.ts +1 -2
- package/src/core/applications/application.ts +12 -9
- package/src/core/applications/interface.ts +126 -0
- package/src/core/projects.ts +1 -1
- package/src/core/user-applications/core-app.ts +1 -1
- package/src/core/user-applications/studios/workspace.ts +5 -1
- package/src/core/user-applications/user-application.ts +2 -2
- package/src/system/load-federated-module.ts +1 -2
- package/src/system/module-federation.ts +116 -0
- package/src/system/remote.machine.ts +1 -1
- package/src/system/remotes.machine.ts +1 -1
- package/src/system/root.machine.ts +5 -5
- package/src/system/service.machine.ts +1 -1
- package/src/system/services.machine.ts +1 -1
package/dist/system.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","sources":["../src/system/load-federated-module.ts","../src/system/remote.machine.ts","../src/system/auth.machine.ts","../src/system/inspect.ts","../src/system/remotes.machine.ts","../src/system/service.machine.ts","../src/system/services.machine.ts","../src/system/system-preferences.machine.ts","../src/system/telemetry.machine.ts","../src/system/root.machine.ts"],"sourcesContent":["import type { FederationInstance } from \"@sanity/federation/runtime\";\n\nimport { logger } from \"../core/log\";\n\n/**\n * A module exposed by an application's federation remote.\n *\n * @public\n */\nexport interface FederatedModuleRef {\n /**\n * Fully-qualified module id — `${appId}/${expose}`, e.g.\n * `studio-1/views/feed/panel` (a view component) or `studio-1/App` (the\n * full-page view). The remote's name is its first segment.\n */\n moduleId: string;\n /** The remote's `mf-manifest.json` URL (served from the app's origin). */\n entry: string;\n}\n\n/**\n * Register an app's federation remote (idempotent) and load one of its exposes\n * by its fully-qualified `moduleId`. Failures propagate, so the caller drives\n * its own error handling (e.g. a machine's error state with the original\n * cause). For the render-empty-on-failure policy, use {@link loadFederatedModule}.\n */\nexport async function loadRemoteModule<T>(\n instance: FederationInstance,\n { moduleId, entry }: FederatedModuleRef,\n): Promise<T | null> {\n // The remote name is the first segment; the expose is the remainder.\n const name = moduleId.slice(0, moduleId.indexOf(\"/\"));\n instance.registerRemotes([{ name, entry }]);\n return (await instance.loadRemote<T | null>(moduleId)) ?? null;\n}\n\n/**\n * {@link loadRemoteModule} with the render-empty-on-failure policy: any failure\n * resolves to `null` (and logs), so every caller handles a missing interface\n * the same way — a panel renders empty, a worker doesn't spawn.\n *\n * @public\n */\nexport async function loadFederatedModule<T>(\n instance: FederationInstance,\n ref: FederatedModuleRef,\n): Promise<T | null> {\n try {\n return await loadRemoteModule<T>(instance, ref);\n } catch (error) {\n logger.error(`Failed to load federated module \"${ref.moduleId}\"`, error);\n return null;\n }\n}\n","import type { FederationInstance } from \"@sanity/federation/runtime\";\nimport { assign, fromPromise, sendParent, setup } from \"xstate\";\n\nimport { loadRemoteModule } from \"./load-federated-module\";\n\n/**\n * @public\n */\nexport interface RemoteRenderOptions {\n basePath?: string;\n scheme?: \"light\" | \"dark\";\n /**\n * This is a temporary measure designed to authenticate federated\n * studios & SDK apps before we write a working protocol.\n */\n unstable_temporaryToken?: string | null;\n}\n\n/**\n * A loaded render-contract module. `TProps` is what its `render` accepts —\n * `RemoteRenderOptions` for an application's full-page view, the view's props\n * for a dock-panel component.\n * @public\n */\nexport interface LoadedRemoteModule<TProps = RemoteRenderOptions> {\n render: (rootElement: HTMLElement, props?: TProps) => () => void;\n}\n\n/**\n * A worker service's loader module — the `worker` interface's expose. Carries\n * the worker bundle URL (root-relative to the app origin) for the host to\n * bootstrap, not a render function; the services counterpart of\n * {@link LoadedRemoteModule}.\n * @public\n */\nexport interface ServiceLoaderModule {\n url: string;\n type: string;\n name: string;\n version: number;\n}\n\n/**\n * The federated-module shape each interface type exposes, keyed by\n * `interface_type`. Every interface — `panel`, `app`, `worker` — loads through\n * the same {@link remoteLogic} lifecycle; this maps what its loaded module looks\n * like so each consumer narrows the machine's shape-agnostic `module` to the\n * right type: a render contract for `panel`/`app` (rendered by an island), a\n * worker loader for `worker` (run as a Web Worker, never rendered).\n * @public\n */\nexport interface RemoteModuleByInterfaceType {\n panel: LoadedRemoteModule;\n app: LoadedRemoteModule;\n worker: ServiceLoaderModule;\n}\n\n/**\n * @public\n */\nexport interface RemoteError {\n message: string;\n cause: unknown;\n}\n\n/**\n * Thrown by a render consumer (e.g. the island) when a loaded module doesn't\n * expose a `render` function. Render-specific — `remoteLogic` itself is\n * shape-agnostic, so this lives with the consumer that needs the contract, not\n * the loader. Surfaced via `RemoteError.cause` for consumers that discriminate.\n * @public\n */\nexport class ModuleShapeError extends Error {\n constructor(remoteId: string) {\n super(`Remote \"${remoteId}\" did not expose a render function`);\n }\n}\n\n/**\n * Thrown by the load actor when a remote's expose resolves empty — the module\n * isn't published, or `loadRemote` returned nothing. Generic across interface\n * types; the shape-specific check (a render function, a worker URL) is the\n * consumer's, since `remoteLogic` loads every interface the same way.\n * @internal\n */\nexport class ModuleLoadError extends Error {\n constructor(remoteId: string) {\n super(`Remote module \"${remoteId}\" failed to load`);\n }\n}\n\n/**\n * @internal\n */\nexport interface RemoteInput {\n /** Fully-qualified module id — `${appId}/${expose}`. One child per moduleId. */\n moduleId: string;\n entry: string;\n instance: FederationInstance;\n}\n\ntype RemoteContext = RemoteInput & {\n /** The loaded module, shape-agnostic — each consumer narrows it. @see {@link RemoteModuleByInterfaceType} */\n module: unknown;\n error: RemoteError | null;\n};\n\nconst loadLogic = fromPromise<unknown, RemoteInput>(async ({ input }) => {\n const remoteModule = await loadRemoteModule<unknown>(input.instance, {\n moduleId: input.moduleId,\n entry: input.entry,\n });\n // The loader is interface-agnostic: it only guarantees a module came back.\n // Render-vs-worker shape validation is the consumer's (a panel/app island\n // checks `render`; a service checks `url`).\n if (remoteModule == null) {\n throw new ModuleLoadError(input.moduleId);\n }\n return remoteModule;\n});\n\n/**\n * Lifecycle machine for a single federated interface module — an application's\n * `App` entry, one view component, or a worker service's loader. Interface-\n * agnostic: it loads and tracks any module, leaving the shape contract\n * (render vs. worker URL) to the consumer.\n *\n * Spawned by the {@link remotesLogic} supervisor on demand, one per remote id\n * (`${appId}/${moduleId}`). Each instance owns one module's load lifecycle:\n * `loading` → `loaded | error`. Tags (`loading` / `ready` / `failed`) drive the\n * UI contract — state names are internal.\n *\n * The machine sends a `remote.settled` event to its parent on entry to\n * either terminal state, reserved for future supervision/retry.\n *\n * @internal\n */\nexport const remoteLogic = setup({\n types: {\n input: {} as RemoteInput,\n context: {} as RemoteContext,\n tags: {} as \"loading\" | \"ready\" | \"failed\",\n },\n actors: {\n load: loadLogic,\n },\n actions: {\n setModule: assign({\n module: (_, params: { module: unknown }) => params.module,\n error: () => null,\n }),\n setError: assign({\n module: () => null,\n error: (_, params: { error: unknown }) => normaliseError(params.error),\n }),\n },\n}).createMachine({\n id: \"remote\",\n initial: \"loading\",\n context: ({ input }) => ({\n ...input,\n module: null,\n error: null,\n }),\n states: {\n loading: {\n tags: [\"loading\"],\n invoke: {\n src: \"load\",\n input: ({ context }) => ({\n moduleId: context.moduleId,\n entry: context.entry,\n instance: context.instance,\n }),\n onDone: {\n target: \"loaded\",\n actions: [\n {\n type: \"setModule\",\n params: ({ event }) => ({ module: event.output }),\n },\n ],\n },\n onError: {\n target: \"error\",\n actions: [\n {\n type: \"setError\",\n params: ({ event }) => ({ error: event.error }),\n },\n ],\n },\n },\n },\n loaded: {\n tags: [\"ready\"],\n entry: sendParent(({ context }) => ({\n type: \"remote.settled\" as const,\n moduleId: context.moduleId,\n status: \"loaded\" as const,\n })),\n },\n error: {\n tags: [\"failed\"],\n entry: sendParent(({ context }) => ({\n type: \"remote.settled\" as const,\n moduleId: context.moduleId,\n status: \"error\" as const,\n })),\n },\n },\n});\n\nfunction normaliseError(error: unknown): RemoteError {\n if (error instanceof Error) {\n return { message: error.message, cause: error };\n }\n return { message: String(error), cause: error };\n}\n","import {\n type AuthState,\n AuthStateType,\n type CurrentUser,\n getAuthState,\n type LoggedInAuthState,\n logout,\n type SanityInstance,\n} from \"@sanity/sdk\";\nimport { assign, fromObservable, fromPromise, setup } from \"xstate\";\n\nimport type { OSBaseInput } from \"./root.machine\";\n\n/**\n * @internal\n */\nexport interface AuthInput extends OSBaseInput {}\n\nconst authStateLogic = fromObservable<AuthState, AuthInput>(\n ({ input }) => getAuthState(input.instance).observable,\n);\n\n/**\n * @internal\n */\nexport interface LogoutInput extends OSBaseInput {}\n\nconst logoutActorLogic = fromPromise<void, LogoutInput>(async ({ input }) => {\n await logout(input.instance);\n});\n\ntype AuthContext = {\n instance: SanityInstance;\n token: string | null;\n currentUser: CurrentUser | null;\n error: unknown;\n};\n\ntype AuthEvent = { type: \"auth.logout\" };\n\nexport const authLogic = setup({\n types: {\n input: {} as AuthInput,\n context: {} as AuthContext,\n events: {} as AuthEvent,\n tags: {} as \"authenticating\" | \"authenticated\" | \"error\",\n },\n actors: {\n authState: authStateLogic,\n logoutActor: logoutActorLogic,\n },\n delays: {\n authTimeout: 30_000,\n },\n guards: {\n isLoggedInComplete: (_, params: { state: AuthState | undefined }) =>\n params.state?.type === AuthStateType.LOGGED_IN &&\n Boolean((params.state as LoggedInAuthState).token) &&\n (params.state as LoggedInAuthState).currentUser !== null,\n isAuthState: (\n _,\n params: { state: AuthState | undefined; type: AuthStateType },\n ) => params.state?.type === params.type,\n },\n actions: {\n setLoggedIn: assign({\n token: (_, params: { token: string; currentUser: CurrentUser }) =>\n params.token,\n currentUser: (_, params: { token: string; currentUser: CurrentUser }) =>\n params.currentUser,\n error: () => null,\n }),\n clearAuth: assign({\n token: () => null,\n currentUser: () => null,\n error: () => null,\n }),\n setError: assign({\n token: () => null,\n currentUser: () => null,\n error: (_, params: { error: unknown }) => params.error,\n }),\n },\n}).createMachine({\n id: \"auth\",\n initial: \"init\",\n context: ({ input }) => ({\n instance: input.instance,\n token: null,\n currentUser: null,\n error: null,\n }),\n invoke: {\n src: \"authState\",\n input: ({ context }) => ({ instance: context.instance }),\n onSnapshot: [\n {\n guard: {\n type: \"isLoggedInComplete\",\n params: ({ event }) => ({\n state: event.snapshot.context,\n }),\n },\n actions: [\n {\n type: \"setLoggedIn\",\n params: ({ event }) => {\n const state = event.snapshot.context as LoggedInAuthState;\n return {\n token: state.token,\n currentUser: state.currentUser!,\n };\n },\n },\n ],\n target: `.${AuthStateType.LOGGED_IN}`,\n },\n {\n guard: {\n type: \"isAuthState\",\n params: ({ event }) => ({\n state: event.snapshot.context,\n type: AuthStateType.LOGGING_IN,\n }),\n },\n actions: [{ type: \"clearAuth\" }],\n target: `.${AuthStateType.LOGGING_IN}`,\n },\n {\n guard: {\n type: \"isAuthState\",\n params: ({ event }) => ({\n state: event.snapshot.context,\n type: AuthStateType.ERROR,\n }),\n },\n actions: [\n {\n type: \"setError\",\n params: ({ event }) => ({\n error:\n event.snapshot.context?.type === AuthStateType.ERROR\n ? event.snapshot.context.error\n : null,\n }),\n },\n ],\n target: `.${AuthStateType.ERROR}`,\n },\n {\n guard: {\n type: \"isAuthState\",\n params: ({ event }) => ({\n state: event.snapshot.context,\n type: AuthStateType.LOGGED_OUT,\n }),\n },\n actions: [{ type: \"clearAuth\" }],\n target: `.${AuthStateType.LOGGED_OUT}`,\n },\n ],\n },\n states: {\n init: {\n tags: [\"authenticating\"],\n after: {\n authTimeout: {\n actions: [\n {\n type: \"setError\",\n params: () => ({\n error: new Error(\"Authentication timed out\"),\n }),\n },\n ],\n target: AuthStateType.ERROR,\n },\n },\n },\n [AuthStateType.LOGGING_IN]: {\n tags: [\"authenticating\"],\n after: {\n authTimeout: {\n actions: [\n {\n type: \"setError\",\n params: () => ({\n error: new Error(\"Authentication timed out\"),\n }),\n },\n ],\n target: AuthStateType.ERROR,\n },\n },\n },\n [AuthStateType.LOGGED_IN]: {\n tags: [\"authenticated\"],\n on: {\n \"auth.logout\": { target: \"logging-out\" },\n },\n },\n [\"logging-out\"]: {\n invoke: {\n src: \"logoutActor\",\n input: ({ context }) => ({ instance: context.instance }),\n onDone: {\n target: AuthStateType.LOGGED_OUT,\n },\n onError: {\n actions: [\n {\n type: \"setError\",\n params: ({ event }) => ({ error: event.error }),\n },\n ],\n target: AuthStateType.ERROR,\n },\n },\n },\n [AuthStateType.LOGGED_OUT]: {},\n [AuthStateType.ERROR]: { tags: [\"error\"] },\n },\n});\n","import { type ActorRefLike, type InspectionEvent } from \"xstate\";\n\nimport { logger } from \"../core\";\n\n// Mirrors @statelyai/inspect's ActorRefLikeWithData — the inspect\n// callback receives full Actor instances at runtime, but the type is\n// narrowed for @xstate/store compat.\ntype ActorRefWithAncestry = ActorRefLike & {\n id?: string;\n _parent?: ActorRefWithAncestry;\n};\n\nconst actorPath = (ref: ActorRefWithAncestry): string => {\n const segments: string[] = [];\n let current: ActorRefWithAncestry | undefined = ref;\n while (current) {\n segments.unshift(current.id ?? current.sessionId);\n current = current._parent;\n }\n return segments.join(\":\");\n};\n\n/** @internal exported for testing */\nexport const inspect = (event: InspectionEvent): void => {\n const ref = event.actorRef as ActorRefWithAncestry;\n const log = logger.child(actorPath(ref));\n\n switch (event.type) {\n case \"@xstate.snapshot\": {\n log.debug(\"snapshot\", event.snapshot);\n break;\n }\n case \"@xstate.event\":\n log.debug(\"event\", event.event);\n break;\n case \"@xstate.action\":\n log.debug(\"action\", event.action);\n break;\n }\n};\n","import { type FederationInstance } from \"@sanity/federation/runtime\";\nimport { type ActorRefFrom, assign, setup } from \"xstate\";\n\nimport { remoteLogic } from \"./remote.machine\";\n\n/** The shared federation instance, supplied by the root machine. */\ntype RemotesInput = {\n instance: FederationInstance;\n};\n\ntype RemotesContext = {\n instance: FederationInstance;\n children: Map<string, ActorRefFrom<typeof remoteLogic>>;\n};\n\ntype RemotesEvent =\n | { type: \"remote.load.request\"; moduleId: string; entry: string }\n | { type: \"remote.settled\"; moduleId: string; status: \"loaded\" | \"error\" };\n\n/**\n * Supervisor machine for federated modules.\n *\n * Uses the shared {@link FederationInstance} (the `workbench-applications`\n * instance, supplied by the root machine and shared with `services`) and spawns\n * one {@link remoteLogic} child per remote id (`${appId}/${moduleId}`) — so an\n * application's `App` entry and each of its dock-panel view components load (and\n * are tracked) independently. The\n * supervisor is invoked at the root of the OS machine for inspector visibility\n * (`[sanity-workbench:os:remotes]`) — boot does not gate on it.\n *\n * @internal\n */\nexport const remotesLogic = setup({\n types: {\n input: {} as RemotesInput,\n context: {} as RemotesContext,\n events: {} as RemotesEvent,\n },\n actors: {\n remote: remoteLogic,\n },\n guards: {\n remoteNotKnown: ({ context }, params: { moduleId: string }) =>\n !context.children.has(params.moduleId),\n },\n actions: {\n spawnRemote: assign({\n children: (\n { context, spawn },\n params: { moduleId: string; entry: string },\n ) => {\n const ref = spawn(\"remote\", {\n id: params.moduleId,\n systemId: `remotes.${params.moduleId}`,\n input: {\n moduleId: params.moduleId,\n entry: params.entry,\n instance: context.instance,\n },\n });\n return new Map(context.children).set(params.moduleId, ref);\n },\n }),\n },\n}).createMachine({\n id: \"remotes\",\n context: ({ input }) => ({\n instance: input.instance,\n children: new Map(),\n }),\n on: {\n \"remote.load.request\": {\n guard: {\n type: \"remoteNotKnown\",\n params: ({ event }) => ({ moduleId: event.moduleId }),\n },\n actions: [\n {\n type: \"spawnRemote\",\n params: ({ event }) => ({\n moduleId: event.moduleId,\n entry: event.entry,\n }),\n },\n ],\n },\n // Reserved for future supervision/retry. Forwarded by per-remote\n // children on entry to `loaded` or `error`; currently a no-op so the\n // event is part of the typed surface rather than a silent unknown.\n \"remote.settled\": {},\n },\n});\n","import { type FederationInstance } from \"@sanity/federation/runtime\";\nimport { assign, fromCallback, setup } from \"xstate\";\n\nimport { logger } from \"../core/log\";\nimport {\n remoteLogic,\n type RemoteError,\n type ServiceLoaderModule,\n} from \"./remote.machine\";\n\n/**\n * @internal\n */\nexport interface ServiceInput {\n /** Stable child key, `${appId}:${serviceName}`. */\n key: string;\n appId: string;\n serviceName: string;\n /** The app's `mf-manifest.json` URL — the federation remote entry. */\n entry: string;\n instance: FederationInstance;\n}\n\ntype ServiceContext = ServiceInput & {\n /** Resolved worker-bundle URL, absolute on the app origin. */\n workerUrl: string | null;\n};\n\n/** Federation expose segment a service's loader lives under: `services/<name>`. */\nconst SERVICES_MODULE = \"services\";\n\n/**\n * Run the worker. `new Worker(appOriginUrl)` is cross-origin-blocked, and the\n * dev worker isn't self-contained (its root-relative imports would resolve\n * against the wrong origin from a blob). So bootstrap a same-origin worker that\n * dynamically `import()`s the app-origin URL: the worker module then resolves\n * its own imports against the app origin, in dev and build alike. Crashes, a\n * failed load, and the worker's `console.*` (bridged by the wrapper) are\n * surfaced through the host logger (the host owns logging; a worker's own\n * console isn't visible in the page DevTools anyway). Cleanup disposes, then\n * terminates.\n */\nconst runWorker = fromCallback<\n { type: string },\n { key: string; serviceName: string; workerUrl: string }\n>(({ input }) => {\n let worker: Worker | undefined;\n let blobUrl: string | undefined;\n\n try {\n // A same-origin module worker whose only job is to load the real worker\n // from the app origin, so that worker's imports resolve there too.\n const bootstrap = `import(${JSON.stringify(input.workerUrl)})`;\n blobUrl = URL.createObjectURL(\n new Blob([bootstrap], { type: \"text/javascript\" }),\n );\n worker = new Worker(blobUrl, { type: \"module\" });\n\n worker.addEventListener(\"message\", (event: MessageEvent) => {\n if (event.data?.kind === \"workbench.worker.error\") {\n logger.error(\n `Service \"${input.key}\" worker error`,\n event.data.payload?.message,\n );\n } else if (event.data?.kind === \"workbench.worker.log\") {\n // Re-emit the worker's `console.*` (bridged by the wrapper) through the\n // host logger, prefixed with the service name so it shows in the page\n // console.\n const { level, message } = event.data.payload ?? {};\n const emit: Record<string, (message: string) => void> = {\n warn: logger.warn,\n error: logger.error,\n debug: logger.debug,\n };\n (emit[level] ?? logger.info)(\n `[service:${input.serviceName}] ${message ?? \"\"}`,\n );\n }\n });\n\n // A module-load failure (or any uncaught worker error) fires here on the\n // host side — surface it instead of failing silently.\n worker.addEventListener(\"error\", (event: ErrorEvent) => {\n logger.error(\n `Service \"${input.key}\" worker error: ${event.message || String(event)}`,\n );\n });\n } catch (error) {\n logger.error(`Service \"${input.key}\" failed to start its worker`, error);\n }\n\n return () => {\n try {\n worker?.postMessage({ kind: \"workbench.worker.terminate\" });\n } finally {\n worker?.terminate();\n if (blobUrl) URL.revokeObjectURL(blobUrl);\n }\n };\n});\n\n/**\n * Lifecycle machine for a single background service worker.\n *\n * Spawned by the {@link servicesLogic} supervisor, one per `(app, service)`.\n * `loading` loads the worker's loader module through the shared\n * {@link remoteLogic} lifecycle — the same machine every interface (panel, app,\n * worker) loads through — and reads the bundle URL off it. A worker isn't a\n * render module, so it's never handed to an island; `running` bootstraps it as\n * a Web Worker from that URL.\n *\n * @internal\n */\nexport const serviceLogic = setup({\n types: {\n input: {} as ServiceInput,\n context: {} as ServiceContext,\n tags: {} as \"loading\" | \"running\" | \"failed\",\n },\n actors: {\n loadInterface: remoteLogic,\n runWorker,\n },\n}).createMachine({\n id: \"service\",\n initial: \"loading\",\n context: ({ input }) => ({ ...input, workerUrl: null }),\n // The invoked loader `sendParent`s a `remote.settled` on settle; this machine\n // reacts via `onSnapshot` instead, so the event is a no-op here.\n on: { \"remote.settled\": {} },\n states: {\n loading: {\n tags: [\"loading\"],\n invoke: {\n id: \"loader\",\n src: \"loadInterface\",\n input: ({ context }) => ({\n moduleId: `${context.appId}/${SERVICES_MODULE}/${context.serviceName}`,\n entry: context.entry,\n instance: context.instance,\n }),\n onSnapshot: [\n {\n // Loaded and exposing a bundle URL → run it.\n guard: ({ event }) => {\n const module = event.snapshot.context\n .module as ServiceLoaderModule | null;\n return (\n event.snapshot.hasTag(\"ready\") &&\n typeof module?.url === \"string\"\n );\n },\n target: \"running\",\n actions: assign({\n workerUrl: ({ context, event }) => {\n const module = event.snapshot.context\n .module as ServiceLoaderModule;\n // The URL is root-relative to the app; resolve it absolute\n // against the app origin since the loader runs in the host page.\n return new URL(module.url, new URL(context.entry).origin).href;\n },\n }),\n },\n {\n // Load failed, or loaded without a usable URL → no worker.\n guard: ({ event }) => {\n const module = event.snapshot.context\n .module as ServiceLoaderModule | null;\n return (\n event.snapshot.hasTag(\"failed\") ||\n (event.snapshot.hasTag(\"ready\") &&\n typeof module?.url !== \"string\")\n );\n },\n target: \"error\",\n // A worker has no UI surface (unlike a view's error boundary), so a\n // failed load would otherwise be silent — log it through the host.\n actions: ({ context, event }) => {\n const cause = (event.snapshot.context.error as RemoteError | null)\n ?.message;\n logger.error(\n `Service \"${context.key}\" failed to load its worker${\n cause ? `: ${cause}` : \"\"\n }`,\n );\n },\n },\n ],\n },\n },\n running: {\n tags: [\"running\"],\n invoke: {\n src: \"runWorker\",\n input: ({ context }) => ({\n key: context.key,\n serviceName: context.serviceName,\n // `workerUrl` is set on entry to `running` from `loading`'s output.\n workerUrl: context.workerUrl!,\n }),\n },\n },\n error: {\n tags: [\"failed\"],\n },\n },\n});\n","import { type FederationInstance } from \"@sanity/federation/runtime\";\nimport { type ActorRefFrom, enqueueActions, setup } from \"xstate\";\n\nimport { serviceLogic } from \"./service.machine\";\n\n/** The shared federation instance, supplied by the root machine. */\ntype ServicesInput = {\n instance: FederationInstance;\n};\n\ntype ServicesContext = {\n instance: FederationInstance;\n children: Map<string, ActorRefFrom<typeof serviceLogic>>;\n};\n\n/**\n * The full set of background services the workbench should currently be\n * running, re-sent whenever the application list — or any app's declared\n * interfaces — changes. The supervisor reconciles its children against it.\n */\ntype ServicesEvent = {\n type: \"services.sync\";\n services: ReadonlyArray<{\n appId: string;\n serviceName: string;\n entry: string;\n }>;\n};\n\n/** Stable child key for a service: `${appId}:${serviceName}`. */\nfunction serviceKey(appId: string, serviceName: string): string {\n return `${appId}:${serviceName}`;\n}\n\n/**\n * Supervisor machine for background service workers.\n *\n * Uses the shared {@link FederationInstance} (supplied by the root machine and\n * shared with `remotes`, so an app's remote is registered once for both its\n * views and its workers) and spawns one {@link serviceLogic} child per\n * `(app, service)`. Invoked at the root of the OS machine for inspector\n * visibility — boot does not gate on it.\n *\n * On every `services.sync` it reconciles its children against the desired set:\n * a newly-declared worker is spawned, and a worker whose declaration was\n * removed (e.g. deleted from `sanity.cli.ts` during dev — FR-024) is stopped,\n * which disposes its `runWorker` callback and terminates the Web Worker. A\n * service `src` edit still triggers a Vite full page reload (workers have no\n * HMR boundary), which reboots the workbench and respawns with the new code.\n *\n * @internal\n */\nexport const servicesLogic = setup({\n types: {\n input: {} as ServicesInput,\n context: {} as ServicesContext,\n events: {} as ServicesEvent,\n },\n actors: {\n service: serviceLogic,\n },\n actions: {\n /**\n * Reconcile the running workers against the desired set: spawn the ones not\n * yet running, stop (and forget) the ones no longer declared.\n */\n syncServices: enqueueActions(({ context, event, enqueue }) => {\n const desired = new Map(\n event.services.map((service) => [\n serviceKey(service.appId, service.serviceName),\n service,\n ]),\n );\n\n // Stop + forget workers whose declaration was removed. Stopping the child\n // disposes its `runWorker` callback, which terminates the Web Worker.\n for (const [key, ref] of context.children) {\n if (!desired.has(key)) enqueue.stopChild(ref);\n }\n\n enqueue.assign({\n children: ({ context: ctx, spawn }) => {\n const next = new Map<string, ActorRefFrom<typeof serviceLogic>>();\n // Keep the children still declared.\n for (const [key, ref] of ctx.children) {\n if (desired.has(key)) next.set(key, ref);\n }\n // Spawn the newly-declared ones.\n for (const [key, service] of desired) {\n if (next.has(key)) continue;\n next.set(\n key,\n spawn(\"service\", {\n id: key,\n systemId: `services.${key}`,\n input: {\n key,\n appId: service.appId,\n serviceName: service.serviceName,\n entry: service.entry,\n instance: ctx.instance,\n },\n }),\n );\n }\n return next;\n },\n });\n }),\n },\n}).createMachine({\n id: \"services\",\n context: ({ input }) => ({\n instance: input.instance,\n children: new Map(),\n }),\n on: {\n \"services.sync\": { actions: \"syncServices\" },\n },\n});\n","import { assign, fromCallback, sendTo, setup } from \"xstate\";\n\ntype ColorScheme = \"light\" | \"dark\";\n\ntype ColorSchemePreference = \"system\" | ColorScheme;\n\n/**\n * The system-preferences machine's context. Consumers read fields directly\n * (e.g. via `useSelector`) rather than going through a resolver utility —\n * the action handlers keep `colorScheme` in sync with `preferredColorScheme`\n * and `osColorScheme`.\n *\n * Note: `colorScheme` is intentionally stored as derived state in context so\n * consumers can read the resolved value directly without a utility. The\n * action handlers below are the single source of truth for the resolution.\n * @public\n */\nexport type SystemPreferencesContext = {\n /** User's color scheme choice; `system` defers to the OS preference. */\n preferredColorScheme: ColorSchemePreference;\n /** Last reported OS color scheme. Used to resolve `colorScheme` when the\n * preference is `system`. */\n osColorScheme: ColorScheme;\n /** Resolved color scheme — what the UI should render. Recomputed by the\n * action handlers whenever an input changes. */\n colorScheme: ColorScheme;\n};\n\nconst DEFAULT_PREFERRED_COLOR_SCHEME: ColorSchemePreference = \"system\";\nconst DEFAULT_OS_COLOR_SCHEME: ColorScheme = \"light\";\n\n/**\n * Events the system-preferences machine accepts. Both originate from the\n * host's adapter — `preferredColorScheme.set` is also forwarded back to it\n * so it can persist the user's choice.\n * @public\n */\nexport type SystemPreferencesEvent =\n | {\n type: \"preferredColorScheme.set\";\n preferredColorScheme: ColorSchemePreference;\n }\n | {\n type: \"osColorScheme.set\";\n osColorScheme: ColorScheme;\n };\n\n/**\n * Adapter interface the host implements to give the system-preferences\n * machine access to the user's environment (OS color scheme, persistent\n * storage, cross-context change notifications).\n *\n * The package owns all orchestration — synchronous seeding, idempotent\n * persistence, mapping cleared storage to `\"system\"`. The host's\n * implementation is pure DOM/storage glue: read, write, subscribe.\n * @public\n */\nexport type SystemPreferencesAdapter = {\n /** Read the user's stored preference. `null` means \"no preference set\"\n * (the machine treats this as `\"system\"`). */\n getPreferredColorScheme: () => ColorSchemePreference | null;\n /** Write the user's preference to persistent storage. */\n persistPreferredColorScheme: (value: ColorSchemePreference) => void;\n /** Subscribe to cross-context preference changes (e.g. another tab\n * writing to the shared storage). The callback receives the new stored\n * value (or `null` if it was cleared). Returns an unsubscribe function. */\n subscribePreferredColorScheme: (\n callback: (next: ColorSchemePreference | null) => void,\n ) => () => void;\n /** Read the current OS-detected color scheme. */\n getOsColorScheme: () => ColorScheme;\n /** Subscribe to OS color-scheme changes (e.g. user flipping dark mode).\n * Returns an unsubscribe function. */\n subscribeOsColorScheme: (callback: (next: ColorScheme) => void) => () => void;\n};\n\nconst resolveColorScheme = (\n preferred: ColorSchemePreference,\n osColorScheme: ColorScheme,\n): ColorScheme => (preferred === \"system\" ? osColorScheme : preferred);\n\n// Internal bridge actor — subscribes to the host's adapter for runtime\n// changes and persists user-driven preference changes when the parent\n// forwards them. No-op if the host didn't pass an adapter (SSR, tests).\ntype AdapterBridgeReceiveEvent = Extract<\n SystemPreferencesEvent,\n { type: \"preferredColorScheme.set\" }\n>;\n\nconst adapterBridgeLogic = fromCallback<\n AdapterBridgeReceiveEvent,\n SystemPreferencesAdapter | undefined,\n SystemPreferencesEvent\n>(({ input: adapter, sendBack, receive }) => {\n if (!adapter) return;\n\n const unsubscribePreferredColorScheme = adapter.subscribePreferredColorScheme(\n (next) => {\n // Falls back to `\"system\"` so an external clear (another tab deleting\n // the key) resets the preference rather than silently keeping the\n // previous value.\n sendBack({\n type: \"preferredColorScheme.set\",\n preferredColorScheme: next ?? \"system\",\n });\n },\n );\n\n const unsubscribeOs = adapter.subscribeOsColorScheme((next) => {\n sendBack({ type: \"osColorScheme.set\", osColorScheme: next });\n });\n\n receive((event) => {\n // Idempotent: skip writes that match the current stored value so a\n // `preferredColorScheme.set` originating from cross-context change\n // doesn't loop back into another write.\n if (adapter.getPreferredColorScheme() === event.preferredColorScheme)\n return;\n\n adapter.persistPreferredColorScheme(event.preferredColorScheme);\n });\n\n return () => {\n unsubscribePreferredColorScheme();\n unsubscribeOs();\n };\n});\n\n/**\n * @internal\n */\nexport const systemPreferencesLogic = setup({\n types: {\n input: {} as { adapter?: SystemPreferencesAdapter },\n context: {} as SystemPreferencesContext & {\n adapter: SystemPreferencesAdapter | undefined;\n },\n events: {} as SystemPreferencesEvent,\n },\n actors: {\n adapterBridge: adapterBridgeLogic,\n },\n actions: {\n setPreferredColorScheme: assign({\n preferredColorScheme: (\n _,\n params: { preferredColorScheme: ColorSchemePreference },\n ) => params.preferredColorScheme,\n colorScheme: (\n { context },\n params: { preferredColorScheme: ColorSchemePreference },\n ) =>\n resolveColorScheme(params.preferredColorScheme, context.osColorScheme),\n }),\n setOsColorScheme: assign({\n osColorScheme: (_, params: { osColorScheme: ColorScheme }) =>\n params.osColorScheme,\n colorScheme: ({ context }, params: { osColorScheme: ColorScheme }) =>\n resolveColorScheme(context.preferredColorScheme, params.osColorScheme),\n }),\n },\n}).createMachine({\n id: \"system-preferences\",\n initial: \"ready\",\n context: ({ input }) => {\n const adapter = input.adapter;\n const preferredColorScheme =\n adapter?.getPreferredColorScheme() ?? DEFAULT_PREFERRED_COLOR_SCHEME;\n const osColorScheme =\n adapter?.getOsColorScheme() ?? DEFAULT_OS_COLOR_SCHEME;\n\n return {\n adapter,\n preferredColorScheme,\n osColorScheme,\n colorScheme: resolveColorScheme(preferredColorScheme, osColorScheme),\n };\n },\n invoke: {\n id: \"adapter\",\n src: \"adapterBridge\",\n input: ({ context }) => context.adapter,\n },\n states: {\n ready: {\n on: {\n \"preferredColorScheme.set\": {\n actions: [\n {\n type: \"setPreferredColorScheme\",\n params: ({ event }) => ({\n preferredColorScheme: event.preferredColorScheme,\n }),\n },\n // Forward to the adapter bridge so it can persist the user's\n // choice. The bridge guards against redundant writes, so\n // round-tripping a `preferredColorScheme.set` it sourced itself\n // (e.g. from a `storage` event in another tab) is a no-op.\n sendTo(\"adapter\", ({ event }) => event),\n ],\n },\n \"osColorScheme.set\": {\n actions: [\n {\n type: \"setOsColorScheme\",\n params: ({ event }) => ({\n osColorScheme: event.osColorScheme,\n }),\n },\n ],\n },\n },\n },\n },\n});\n","import { getClient, type SanityInstance } from \"@sanity/sdk\";\nimport {\n type ConsentStatus,\n createBatchedStore,\n createSessionId,\n type TelemetryEvent,\n type TelemetryStore,\n} from \"@sanity/telemetry\";\nimport { assign, fromPromise, setup } from \"xstate\";\n\nimport type { OSBaseInput } from \"./root.machine\";\n\n/**\n * @public\n */\nexport type WorkbenchUserProperties = {\n version: string;\n organizationId: string;\n environment: string;\n userAgent: string;\n};\n\n/**\n * @internal\n */\nexport interface TelemetryInput extends OSBaseInput, WorkbenchUserProperties {}\n\n/**\n * TODO: this shouldn't be unique to the telemetry machine,\n * remove this and set it globally with a single client actor.\n */\nconst TELEMETRY_API_VERSION = \"2024-11-12\";\n/**\n * 30 seconds, in milliseconds, is the default flush interval\n * for the telemetry store.\n */\nconst FLUSH_INTERVAL_MS = 30_000;\n\ntype ConsentResult = { status: ConsentStatus };\n\nconst checkConsentLogic = fromPromise<\n ConsentResult,\n { instance: SanityInstance }\n>(async ({ input, signal }) => {\n try {\n const client = getClient(input.instance, {\n apiVersion: TELEMETRY_API_VERSION,\n });\n return await client.request<ConsentResult>({\n uri: \"/intake/telemetry-status\",\n tag: \"telemetry-consent\",\n signal,\n });\n } catch {\n return { status: \"undetermined\" } satisfies ConsentResult;\n }\n});\n\ntype TelemetryContext = {\n instance: SanityInstance;\n store: TelemetryStore<WorkbenchUserProperties> | null;\n userProperties: WorkbenchUserProperties;\n};\n\ntype TelemetryMachineEvent =\n | { type: \"telemetry.start\" }\n | { type: \"telemetry.stop\" };\n\nexport const telemetryLogic = setup({\n types: {\n input: {} as TelemetryInput,\n context: {} as TelemetryContext,\n events: {} as TelemetryMachineEvent,\n },\n actors: {\n checkConsent: checkConsentLogic,\n },\n guards: {\n isConsentGranted: (_, params: { status: ConsentStatus }) =>\n params.status === \"granted\",\n },\n actions: {\n createStore: assign({\n store: ({ context }) => {\n const sessionId = createSessionId();\n const client = getClient(context.instance, {\n apiVersion: TELEMETRY_API_VERSION,\n });\n const store = createBatchedStore<WorkbenchUserProperties>(sessionId, {\n flushInterval: FLUSH_INTERVAL_MS,\n resolveConsent: () =>\n client.request<{ status: ConsentStatus }>({\n uri: \"/intake/telemetry-status\",\n tag: \"telemetry-consent\",\n }),\n sendEvents: (batch: TelemetryEvent[]) =>\n client.request({\n uri: \"/intake/batch\",\n method: \"POST\",\n body: { batch },\n tag: \"telemetry.batch\",\n }),\n sendBeacon: (batch: TelemetryEvent[]) => {\n if (typeof navigator === \"undefined\") {\n return false;\n }\n return navigator.sendBeacon(\n client.getUrl(\"/intake/batch\"),\n JSON.stringify({ batch }),\n );\n },\n });\n store.logger.updateUserProperties(context.userProperties);\n return store;\n },\n }),\n teardownStore: ({ context }) => {\n context.store?.end();\n },\n },\n}).createMachine({\n id: \"telemetry\",\n initial: \"idle\",\n context: ({ input }) => ({\n instance: input.instance,\n store: null,\n userProperties: {\n version: input.version,\n organizationId: input.organizationId,\n environment: input.environment,\n userAgent: input.userAgent,\n },\n }),\n states: {\n idle: {\n on: {\n \"telemetry.start\": {\n target: \"checkingConsent\",\n },\n },\n },\n checkingConsent: {\n invoke: {\n src: \"checkConsent\",\n input: ({ context }) => ({\n instance: context.instance,\n }),\n onDone: [\n {\n guard: {\n type: \"isConsentGranted\",\n params: ({ event }) => ({\n status: event.output.status,\n }),\n },\n actions: [{ type: \"createStore\" }],\n target: \"active\",\n },\n {\n target: \"denied\",\n },\n ],\n },\n },\n active: {\n tags: [\"telemetry-resolved\"],\n exit: [{ type: \"teardownStore\" }],\n on: {\n \"telemetry.stop\": { target: \"stopped\" },\n },\n },\n stopped: {\n type: \"final\",\n },\n denied: {\n tags: [\"telemetry-resolved\"],\n },\n },\n});\n","import {\n createInstance,\n type FederationInstance,\n} from \"@sanity/federation/runtime\";\nimport { log } from \"@sanity/federation/runtime/plugins/log\";\nimport { createSanityInstance, type SanityInstance } from \"@sanity/sdk\";\nimport { raise, sendTo, setup, type ActorOptions } from \"xstate\";\n\nimport { logger } from \"../core/log\";\nimport { authLogic } from \"./auth.machine\";\nimport { inspect } from \"./inspect\";\nimport { remotesLogic } from \"./remotes.machine\";\nimport { servicesLogic } from \"./services.machine\";\nimport {\n type SystemPreferencesAdapter,\n systemPreferencesLogic,\n} from \"./system-preferences.machine\";\nimport {\n telemetryLogic,\n type WorkbenchUserProperties,\n} from \"./telemetry.machine\";\n\ntype OSInput = WorkbenchUserProperties & {\n systemPreferencesAdapter?: SystemPreferencesAdapter;\n};\n\ntype OSContext = {\n instance: SanityInstance;\n /**\n * The single module-federation instance every interface loads through —\n * shared by the `remotes` (views) and `services` (workers) supervisors so an\n * app's remote is registered once for all its interfaces.\n */\n federationInstance: FederationInstance;\n userProperties: WorkbenchUserProperties;\n systemPreferencesAdapter: SystemPreferencesAdapter | undefined;\n};\n\n/**\n * The base inputs for the OS machine.\n * @internal\n */\nexport interface OSBaseInput extends Pick<OSContext, \"instance\"> {}\n\n/**\n * The sanity OS machine, responsible for managing the global state of the OS.\n * @public\n * @example\n * ```ts\n * import { os, createOSOptions } from \"@sanity/workbench/system\";\n * import { useActor } from \"@xstate/react\";\n *\n * const [state, send] = useActor(os, createOSOptions({\n * version: \"1.0.0\",\n * organizationId: \"...\",\n * environment: \"production\",\n * userAgent: navigator.userAgent,\n * }));\n * ```\n */\nexport const os = setup({\n types: {\n input: {} as OSInput,\n context: {} as OSContext,\n events: {} as\n | { type: \"boot.auth.ready\" }\n | { type: \"boot.auth.failed\" }\n | { type: \"boot.telemetry.ready\" },\n // https://github.com/statelyai/xstate/issues/5515\n children: {} as {\n auth: \"auth\";\n telemetry: \"telemetry\";\n \"system-preferences\": \"systemPreferences\";\n remotes: \"remotes\";\n services: \"services\";\n },\n },\n actors: {\n auth: authLogic,\n telemetry: telemetryLogic,\n systemPreferences: systemPreferencesLogic,\n remotes: remotesLogic,\n services: servicesLogic,\n },\n guards: {\n hasTag: (_, params: { hasTag: boolean }) => params.hasTag,\n },\n actions: {\n raiseAuthReady: raise({ type: \"boot.auth.ready\" }),\n raiseAuthFailed: raise({ type: \"boot.auth.failed\" }),\n raiseTelemetryReady: raise({\n type: \"boot.telemetry.ready\",\n }),\n startTelemetry: sendTo(\"telemetry\", {\n type: \"telemetry.start\",\n }),\n },\n}).createMachine({\n id: \"os\",\n context: ({ input }) => ({\n instance: createSanityInstance(),\n federationInstance: createInstance({\n name: \"workbench-applications\",\n plugins: [log(logger.debug)],\n }),\n userProperties: {\n version: input.version,\n organizationId: input.organizationId,\n environment: input.environment,\n userAgent: input.userAgent,\n },\n systemPreferencesAdapter: input.systemPreferencesAdapter,\n }),\n initial: \"booting\",\n invoke: [\n {\n id: \"auth\",\n systemId: \"auth\",\n src: \"auth\",\n input: ({ context }) => ({ instance: context.instance }),\n onSnapshot: [\n {\n guard: {\n type: \"hasTag\",\n params: ({ event }) => ({\n hasTag: event.snapshot.hasTag(\"authenticated\"),\n }),\n },\n actions: [{ type: \"raiseAuthReady\" }],\n },\n {\n guard: {\n type: \"hasTag\",\n params: ({ event }) => ({\n hasTag: event.snapshot.hasTag(\"error\"),\n }),\n },\n actions: [{ type: \"raiseAuthFailed\" }],\n },\n ],\n },\n {\n id: \"telemetry\",\n systemId: \"telemetry\",\n src: \"telemetry\",\n input: ({ context }) => ({\n instance: context.instance,\n ...context.userProperties,\n }),\n onSnapshot: [\n {\n guard: {\n type: \"hasTag\",\n params: ({ event }) => ({\n hasTag: event.snapshot.hasTag(\"telemetry-resolved\"),\n }),\n },\n actions: [{ type: \"raiseTelemetryReady\" }],\n },\n ],\n },\n {\n id: \"system-preferences\",\n systemId: \"system-preferences\",\n src: \"systemPreferences\",\n input: ({ context }) => ({ adapter: context.systemPreferencesAdapter }),\n },\n {\n id: \"remotes\",\n systemId: \"remotes\",\n src: \"remotes\",\n input: ({ context }) => ({ instance: context.federationInstance }),\n },\n {\n id: \"services\",\n systemId: \"services\",\n src: \"services\",\n input: ({ context }) => ({ instance: context.federationInstance }),\n },\n ],\n states: {\n booting: {\n initial: \"auth\",\n states: {\n auth: {\n on: {\n \"boot.auth.ready\": {\n target: \"telemetry\",\n actions: [{ type: \"startTelemetry\" }],\n },\n \"boot.auth.failed\": { target: \"error\" },\n },\n },\n telemetry: {\n on: {\n \"boot.telemetry.ready\": { target: \"done\" },\n },\n },\n error: {},\n done: { type: \"final\" },\n },\n onDone: { target: \"running\" },\n },\n running: {\n type: \"parallel\",\n },\n },\n});\n\n/**\n * Creates a set of default options for the OS machine. Forwards the workbench\n * user properties to the machine's input and wires the structured-logging\n * `inspect` callback. Browser-specific concerns (color-scheme seeding,\n * persistence) live in the {@link SystemPreferencesAdapter} the host passes\n * via `systemPreferencesAdapter`.\n * @public\n */\nexport function createOSOptions(input: OSInput) {\n return {\n id: \"os\",\n input,\n inspect,\n } satisfies ActorOptions<typeof os>;\n}\n"],"names":["log"],"mappings":";;;;;;;AA0BA,eAAsB,iBACpB,UACA,EAAE,UAAU,SACO;AAEnB,QAAM,OAAO,SAAS,MAAM,GAAG,SAAS,QAAQ,GAAG,CAAC;AACpD,SAAA,SAAS,gBAAgB,CAAC,EAAE,MAAM,MAAA,CAAO,CAAC,GAClC,MAAM,SAAS,WAAqB,QAAQ,KAAM;AAC5D;AASA,eAAsB,oBACpB,UACA,KACmB;AACnB,MAAI;AACF,WAAO,MAAM,iBAAoB,UAAU,GAAG;AAAA,EAChD,SAAS,OAAO;AACd,WAAA,OAAO,MAAM,oCAAoC,IAAI,QAAQ,KAAK,KAAK,GAChE;AAAA,EACT;AACF;ACmBO,MAAM,yBAAyB,MAAM;AAAA,EAC1C,YAAY,UAAkB;AAC5B,UAAM,WAAW,QAAQ,oCAAoC;AAAA,EAC/D;AACF;AASO,MAAM,wBAAwB,MAAM;AAAA,EACzC,YAAY,UAAkB;AAC5B,UAAM,kBAAkB,QAAQ,kBAAkB;AAAA,EACpD;AACF;AAkBA,MAAM,YAAY,YAAkC,OAAO,EAAE,YAAY;AACvE,QAAM,eAAe,MAAM,iBAA0B,MAAM,UAAU;AAAA,IACnE,UAAU,MAAM;AAAA,IAChB,OAAO,MAAM;AAAA,EAAA,CACd;AAID,MAAI,gBAAgB;AAClB,UAAM,IAAI,gBAAgB,MAAM,QAAQ;AAE1C,SAAO;AACT,CAAC,GAkBY,cAAc,MAAM;AAAA,EAC/B,OAAO;AAAA,IACL,OAAO,CAAA;AAAA,IACP,SAAS,CAAA;AAAA,IACT,MAAM,CAAA;AAAA,EAAC;AAAA,EAET,QAAQ;AAAA,IACN,MAAM;AAAA,EAAA;AAAA,EAER,SAAS;AAAA,IACP,WAAW,OAAO;AAAA,MAChB,QAAQ,CAAC,GAAG,WAAgC,OAAO;AAAA,MACnD,OAAO,MAAM;AAAA,IAAA,CACd;AAAA,IACD,UAAU,OAAO;AAAA,MACf,QAAQ,MAAM;AAAA,MACd,OAAO,CAAC,GAAG,WAA+B,eAAe,OAAO,KAAK;AAAA,IAAA,CACtE;AAAA,EAAA;AAEL,CAAC,EAAE,cAAc;AAAA,EACf,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,SAAS,CAAC,EAAE,aAAa;AAAA,IACvB,GAAG;AAAA,IACH,QAAQ;AAAA,IACR,OAAO;AAAA,EAAA;AAAA,EAET,QAAQ;AAAA,IACN,SAAS;AAAA,MACP,MAAM,CAAC,SAAS;AAAA,MAChB,QAAQ;AAAA,QACN,KAAK;AAAA,QACL,OAAO,CAAC,EAAE,eAAe;AAAA,UACvB,UAAU,QAAQ;AAAA,UAClB,OAAO,QAAQ;AAAA,UACf,UAAU,QAAQ;AAAA,QAAA;AAAA,QAEpB,QAAQ;AAAA,UACN,QAAQ;AAAA,UACR,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,QAAQ,CAAC,EAAE,MAAA,OAAa,EAAE,QAAQ,MAAM,OAAA;AAAA,YAAO;AAAA,UACjD;AAAA,QACF;AAAA,QAEF,SAAS;AAAA,UACP,QAAQ;AAAA,UACR,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,QAAQ,CAAC,EAAE,MAAA,OAAa,EAAE,OAAO,MAAM,MAAA;AAAA,YAAM;AAAA,UAC/C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEF,QAAQ;AAAA,MACN,MAAM,CAAC,OAAO;AAAA,MACd,OAAO,WAAW,CAAC,EAAE,eAAe;AAAA,QAClC,MAAM;AAAA,QACN,UAAU,QAAQ;AAAA,QAClB,QAAQ;AAAA,MAAA,EACR;AAAA,IAAA;AAAA,IAEJ,OAAO;AAAA,MACL,MAAM,CAAC,QAAQ;AAAA,MACf,OAAO,WAAW,CAAC,EAAE,eAAe;AAAA,QAClC,MAAM;AAAA,QACN,UAAU,QAAQ;AAAA,QAClB,QAAQ;AAAA,MAAA,EACR;AAAA,IAAA;AAAA,EACJ;AAEJ,CAAC;AAED,SAAS,eAAe,OAA6B;AACnD,SAAI,iBAAiB,QACZ,EAAE,SAAS,MAAM,SAAS,OAAO,MAAA,IAEnC,EAAE,SAAS,OAAO,KAAK,GAAG,OAAO,MAAA;AAC1C;ACxMA,MAAM,iBAAiB;AAAA,EACrB,CAAC,EAAE,MAAA,MAAY,aAAa,MAAM,QAAQ,EAAE;AAC9C,GAOM,mBAAmB,YAA+B,OAAO,EAAE,YAAY;AAC3E,QAAM,OAAO,MAAM,QAAQ;AAC7B,CAAC,GAWY,YAAY,MAAM;AAAA,EAC7B,OAAO;AAAA,IACL,OAAO,CAAA;AAAA,IACP,SAAS,CAAA;AAAA,IACT,QAAQ,CAAA;AAAA,IACR,MAAM,CAAA;AAAA,EAAC;AAAA,EAET,QAAQ;AAAA,IACN,WAAW;AAAA,IACX,aAAa;AAAA,EAAA;AAAA,EAEf,QAAQ;AAAA,IACN,aAAa;AAAA,EAAA;AAAA,EAEf,QAAQ;AAAA,IACN,oBAAoB,CAAC,GAAG,WACtB,OAAO,OAAO,SAAS,cAAc,aACrC,EAAS,OAAO,MAA4B,SAC3C,OAAO,MAA4B,gBAAgB;AAAA,IACtD,aAAa,CACX,GACA,WACG,OAAO,OAAO,SAAS,OAAO;AAAA,EAAA;AAAA,EAErC,SAAS;AAAA,IACP,aAAa,OAAO;AAAA,MAClB,OAAO,CAAC,GAAG,WACT,OAAO;AAAA,MACT,aAAa,CAAC,GAAG,WACf,OAAO;AAAA,MACT,OAAO,MAAM;AAAA,IAAA,CACd;AAAA,IACD,WAAW,OAAO;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,aAAa,MAAM;AAAA,MACnB,OAAO,MAAM;AAAA,IAAA,CACd;AAAA,IACD,UAAU,OAAO;AAAA,MACf,OAAO,MAAM;AAAA,MACb,aAAa,MAAM;AAAA,MACnB,OAAO,CAAC,GAAG,WAA+B,OAAO;AAAA,IAAA,CAClD;AAAA,EAAA;AAEL,CAAC,EAAE,cAAc;AAAA,EACf,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,SAAS,CAAC,EAAE,aAAa;AAAA,IACvB,UAAU,MAAM;AAAA,IAChB,OAAO;AAAA,IACP,aAAa;AAAA,IACb,OAAO;AAAA,EAAA;AAAA,EAET,QAAQ;AAAA,IACN,KAAK;AAAA,IACL,OAAO,CAAC,EAAE,QAAA,OAAe,EAAE,UAAU,QAAQ;IAC7C,YAAY;AAAA,MACV;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ,CAAC,EAAE,aAAa;AAAA,YACtB,OAAO,MAAM,SAAS;AAAA,UAAA;AAAA,QACxB;AAAA,QAEF,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,QAAQ,CAAC,EAAE,YAAY;AACrB,oBAAM,QAAQ,MAAM,SAAS;AAC7B,qBAAO;AAAA,gBACL,OAAO,MAAM;AAAA,gBACb,aAAa,MAAM;AAAA,cAAA;AAAA,YAEvB;AAAA,UAAA;AAAA,QACF;AAAA,QAEF,QAAQ,IAAI,cAAc,SAAS;AAAA,MAAA;AAAA,MAErC;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ,CAAC,EAAE,aAAa;AAAA,YACtB,OAAO,MAAM,SAAS;AAAA,YACtB,MAAM,cAAc;AAAA,UAAA;AAAA,QACtB;AAAA,QAEF,SAAS,CAAC,EAAE,MAAM,aAAa;AAAA,QAC/B,QAAQ,IAAI,cAAc,UAAU;AAAA,MAAA;AAAA,MAEtC;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ,CAAC,EAAE,aAAa;AAAA,YACtB,OAAO,MAAM,SAAS;AAAA,YACtB,MAAM,cAAc;AAAA,UAAA;AAAA,QACtB;AAAA,QAEF,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,QAAQ,CAAC,EAAE,aAAa;AAAA,cACtB,OACE,MAAM,SAAS,SAAS,SAAS,cAAc,QAC3C,MAAM,SAAS,QAAQ,QACvB;AAAA,YAAA;AAAA,UACR;AAAA,QACF;AAAA,QAEF,QAAQ,IAAI,cAAc,KAAK;AAAA,MAAA;AAAA,MAEjC;AAAA,QACE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ,CAAC,EAAE,aAAa;AAAA,YACtB,OAAO,MAAM,SAAS;AAAA,YACtB,MAAM,cAAc;AAAA,UAAA;AAAA,QACtB;AAAA,QAEF,SAAS,CAAC,EAAE,MAAM,aAAa;AAAA,QAC/B,QAAQ,IAAI,cAAc,UAAU;AAAA,MAAA;AAAA,IACtC;AAAA,EACF;AAAA,EAEF,QAAQ;AAAA,IACN,MAAM;AAAA,MACJ,MAAM,CAAC,gBAAgB;AAAA,MACvB,OAAO;AAAA,QACL,aAAa;AAAA,UACX,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,QAAQ,OAAO;AAAA,gBACb,OAAO,IAAI,MAAM,0BAA0B;AAAA,cAAA;AAAA,YAC7C;AAAA,UACF;AAAA,UAEF,QAAQ,cAAc;AAAA,QAAA;AAAA,MACxB;AAAA,IACF;AAAA,IAEF,CAAC,cAAc,UAAU,GAAG;AAAA,MAC1B,MAAM,CAAC,gBAAgB;AAAA,MACvB,OAAO;AAAA,QACL,aAAa;AAAA,UACX,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,QAAQ,OAAO;AAAA,gBACb,OAAO,IAAI,MAAM,0BAA0B;AAAA,cAAA;AAAA,YAC7C;AAAA,UACF;AAAA,UAEF,QAAQ,cAAc;AAAA,QAAA;AAAA,MACxB;AAAA,IACF;AAAA,IAEF,CAAC,cAAc,SAAS,GAAG;AAAA,MACzB,MAAM,CAAC,eAAe;AAAA,MACtB,IAAI;AAAA,QACF,eAAe,EAAE,QAAQ,cAAA;AAAA,MAAc;AAAA,IACzC;AAAA,IAED,eAAgB;AAAA,MACf,QAAQ;AAAA,QACN,KAAK;AAAA,QACL,OAAO,CAAC,EAAE,QAAA,OAAe,EAAE,UAAU,QAAQ;QAC7C,QAAQ;AAAA,UACN,QAAQ,cAAc;AAAA,QAAA;AAAA,QAExB,SAAS;AAAA,UACP,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,QAAQ,CAAC,EAAE,MAAA,OAAa,EAAE,OAAO,MAAM,MAAA;AAAA,YAAM;AAAA,UAC/C;AAAA,UAEF,QAAQ,cAAc;AAAA,QAAA;AAAA,MACxB;AAAA,IACF;AAAA,IAEF,CAAC,cAAc,UAAU,GAAG,CAAA;AAAA,IAC5B,CAAC,cAAc,KAAK,GAAG,EAAE,MAAM,CAAC,OAAO,EAAA;AAAA,EAAE;AAE7C,CAAC,GClNK,YAAY,CAAC,QAAsC;AACvD,QAAM,WAAqB,CAAA;AAC3B,MAAI,UAA4C;AAChD,SAAO;AACL,aAAS,QAAQ,QAAQ,MAAM,QAAQ,SAAS,GAChD,UAAU,QAAQ;AAEpB,SAAO,SAAS,KAAK,GAAG;AAC1B,GAGa,UAAU,CAAC,UAAiC;AACvD,QAAM,MAAM,MAAM,UACZA,OAAM,OAAO,MAAM,UAAU,GAAG,CAAC;AAEvC,UAAQ,MAAM,MAAA;AAAA,IACZ,KAAK,oBAAoB;AACvB,MAAAA,KAAI,MAAM,YAAY,MAAM,QAAQ;AACpC;AAAA,IACF;AAAA,IACA,KAAK;AACH,MAAAA,KAAI,MAAM,SAAS,MAAM,KAAK;AAC9B;AAAA,IACF,KAAK;AACH,MAAAA,KAAI,MAAM,UAAU,MAAM,MAAM;AAChC;AAAA,EAAA;AAEN,GCPa,eAAe,MAAM;AAAA,EAChC,OAAO;AAAA,IACL,OAAO,CAAA;AAAA,IACP,SAAS,CAAA;AAAA,IACT,QAAQ,CAAA;AAAA,EAAC;AAAA,EAEX,QAAQ;AAAA,IACN,QAAQ;AAAA,EAAA;AAAA,EAEV,QAAQ;AAAA,IACN,gBAAgB,CAAC,EAAE,QAAA,GAAW,WAC5B,CAAC,QAAQ,SAAS,IAAI,OAAO,QAAQ;AAAA,EAAA;AAAA,EAEzC,SAAS;AAAA,IACP,aAAa,OAAO;AAAA,MAClB,UAAU,CACR,EAAE,SAAS,MAAA,GACX,WACG;AACH,cAAM,MAAM,MAAM,UAAU;AAAA,UAC1B,IAAI,OAAO;AAAA,UACX,UAAU,WAAW,OAAO,QAAQ;AAAA,UACpC,OAAO;AAAA,YACL,UAAU,OAAO;AAAA,YACjB,OAAO,OAAO;AAAA,YACd,UAAU,QAAQ;AAAA,UAAA;AAAA,QACpB,CACD;AACD,eAAO,IAAI,IAAI,QAAQ,QAAQ,EAAE,IAAI,OAAO,UAAU,GAAG;AAAA,MAC3D;AAAA,IAAA,CACD;AAAA,EAAA;AAEL,CAAC,EAAE,cAAc;AAAA,EACf,IAAI;AAAA,EACJ,SAAS,CAAC,EAAE,aAAa;AAAA,IACvB,UAAU,MAAM;AAAA,IAChB,8BAAc,IAAA;AAAA,EAAI;AAAA,EAEpB,IAAI;AAAA,IACF,uBAAuB;AAAA,MACrB,OAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ,CAAC,EAAE,MAAA,OAAa,EAAE,UAAU,MAAM,SAAA;AAAA,MAAS;AAAA,MAErD,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,QAAQ,CAAC,EAAE,aAAa;AAAA,YACtB,UAAU,MAAM;AAAA,YAChB,OAAO,MAAM;AAAA,UAAA;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKF,kBAAkB,CAAA;AAAA,EAAC;AAEvB,CAAC,GC9DK,kBAAkB,YAalB,YAAY,aAGhB,CAAC,EAAE,YAAY;AACf,MAAI,QACA;AAEJ,MAAI;AAGF,UAAM,YAAY,UAAU,KAAK,UAAU,MAAM,SAAS,CAAC;AAC3D,cAAU,IAAI;AAAA,MACZ,IAAI,KAAK,CAAC,SAAS,GAAG,EAAE,MAAM,mBAAmB;AAAA,IAAA,GAEnD,SAAS,IAAI,OAAO,SAAS,EAAE,MAAM,SAAA,CAAU,GAE/C,OAAO,iBAAiB,WAAW,CAAC,UAAwB;AAC1D,UAAI,MAAM,MAAM,SAAS;AACvB,eAAO;AAAA,UACL,YAAY,MAAM,GAAG;AAAA,UACrB,MAAM,KAAK,SAAS;AAAA,QAAA;AAAA,eAEb,MAAM,MAAM,SAAS,wBAAwB;AAItD,cAAM,EAAE,OAAO,QAAA,IAAY,MAAM,KAAK,WAAW,CAAA;AAMjD,SALwD;AAAA,UACtD,MAAM,OAAO;AAAA,UACb,OAAO,OAAO;AAAA,UACd,OAAO,OAAO;AAAA,QAAA,EAEV,KAAK,KAAK,OAAO;AAAA,UACrB,YAAY,MAAM,WAAW,KAAK,WAAW,EAAE;AAAA,QAAA;AAAA,MAEnD;AAAA,IACF,CAAC,GAID,OAAO,iBAAiB,SAAS,CAAC,UAAsB;AACtD,aAAO;AAAA,QACL,YAAY,MAAM,GAAG,mBAAmB,MAAM,WAAW,OAAO,KAAK,CAAC;AAAA,MAAA;AAAA,IAE1E,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO,MAAM,YAAY,MAAM,GAAG,gCAAgC,KAAK;AAAA,EACzE;AAEA,SAAO,MAAM;AACX,QAAI;AACF,cAAQ,YAAY,EAAE,MAAM,6BAAA,CAA8B;AAAA,IAC5D,UAAA;AACE,cAAQ,UAAA,GACJ,WAAS,IAAI,gBAAgB,OAAO;AAAA,IAC1C;AAAA,EACF;AACF,CAAC,GAcY,eAAe,MAAM;AAAA,EAChC,OAAO;AAAA,IACL,OAAO,CAAA;AAAA,IACP,SAAS,CAAA;AAAA,IACT,MAAM,CAAA;AAAA,EAAC;AAAA,EAET,QAAQ;AAAA,IACN,eAAe;AAAA,IACf;AAAA,EAAA;AAEJ,CAAC,EAAE,cAAc;AAAA,EACf,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,SAAS,CAAC,EAAE,MAAA,OAAa,EAAE,GAAG,OAAO,WAAW;;;EAGhD,IAAI,EAAE,kBAAkB,GAAC;AAAA,EACzB,QAAQ;AAAA,IACN,SAAS;AAAA,MACP,MAAM,CAAC,SAAS;AAAA,MAChB,QAAQ;AAAA,QACN,IAAI;AAAA,QACJ,KAAK;AAAA,QACL,OAAO,CAAC,EAAE,eAAe;AAAA,UACvB,UAAU,GAAG,QAAQ,KAAK,IAAI,eAAe,IAAI,QAAQ,WAAW;AAAA,UACpE,OAAO,QAAQ;AAAA,UACf,UAAU,QAAQ;AAAA,QAAA;AAAA,QAEpB,YAAY;AAAA,UACV;AAAA;AAAA,YAEE,OAAO,CAAC,EAAE,YAAY;AACpB,oBAAM,SAAS,MAAM,SAAS,QAC3B;AACH,qBACE,MAAM,SAAS,OAAO,OAAO,KAC7B,OAAO,QAAQ,OAAQ;AAAA,YAE3B;AAAA,YACA,QAAQ;AAAA,YACR,SAAS,OAAO;AAAA,cACd,WAAW,CAAC,EAAE,SAAS,YAAY;AACjC,sBAAM,SAAS,MAAM,SAAS,QAC3B;AAGH,uBAAO,IAAI,IAAI,OAAO,KAAK,IAAI,IAAI,QAAQ,KAAK,EAAE,MAAM,EAAE;AAAA,cAC5D;AAAA,YAAA,CACD;AAAA,UAAA;AAAA,UAEH;AAAA;AAAA,YAEE,OAAO,CAAC,EAAE,YAAY;AACpB,oBAAM,SAAS,MAAM,SAAS,QAC3B;AACH,qBACE,MAAM,SAAS,OAAO,QAAQ,KAC7B,MAAM,SAAS,OAAO,OAAO,KAC5B,OAAO,QAAQ,OAAQ;AAAA,YAE7B;AAAA,YACA,QAAQ;AAAA;AAAA;AAAA,YAGR,SAAS,CAAC,EAAE,SAAS,YAAY;AAC/B,oBAAM,QAAS,MAAM,SAAS,QAAQ,OAClC;AACJ,qBAAO;AAAA,gBACL,YAAY,QAAQ,GAAG,8BACrB,QAAQ,KAAK,KAAK,KAAK,EACzB;AAAA,cAAA;AAAA,YAEJ;AAAA,UAAA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEF,SAAS;AAAA,MACP,MAAM,CAAC,SAAS;AAAA,MAChB,QAAQ;AAAA,QACN,KAAK;AAAA,QACL,OAAO,CAAC,EAAE,eAAe;AAAA,UACvB,KAAK,QAAQ;AAAA,UACb,aAAa,QAAQ;AAAA;AAAA,UAErB,WAAW,QAAQ;AAAA,QAAA;AAAA,MACrB;AAAA,IACF;AAAA,IAEF,OAAO;AAAA,MACL,MAAM,CAAC,QAAQ;AAAA,IAAA;AAAA,EACjB;AAEJ,CAAC;AChLD,SAAS,WAAW,OAAe,aAA6B;AAC9D,SAAO,GAAG,KAAK,IAAI,WAAW;AAChC;AAoBO,MAAM,gBAAgB,MAAM;AAAA,EACjC,OAAO;AAAA,IACL,OAAO,CAAA;AAAA,IACP,SAAS,CAAA;AAAA,IACT,QAAQ,CAAA;AAAA,EAAC;AAAA,EAEX,QAAQ;AAAA,IACN,SAAS;AAAA,EAAA;AAAA,EAEX,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,IAKP,cAAc,eAAe,CAAC,EAAE,SAAS,OAAO,cAAc;AAC5D,YAAM,UAAU,IAAI;AAAA,QAClB,MAAM,SAAS,IAAI,CAAC,YAAY;AAAA,UAC9B,WAAW,QAAQ,OAAO,QAAQ,WAAW;AAAA,UAC7C;AAAA,QAAA,CACD;AAAA,MAAA;AAKH,iBAAW,CAAC,KAAK,GAAG,KAAK,QAAQ;AAC1B,gBAAQ,IAAI,GAAG,KAAG,QAAQ,UAAU,GAAG;AAG9C,cAAQ,OAAO;AAAA,QACb,UAAU,CAAC,EAAE,SAAS,KAAK,YAAY;AACrC,gBAAM,2BAAW,IAAA;AAEjB,qBAAW,CAAC,KAAK,GAAG,KAAK,IAAI;AACvB,oBAAQ,IAAI,GAAG,KAAG,KAAK,IAAI,KAAK,GAAG;AAGzC,qBAAW,CAAC,KAAK,OAAO,KAAK;AACvB,iBAAK,IAAI,GAAG,KAChB,KAAK;AAAA,cACH;AAAA,cACA,MAAM,WAAW;AAAA,gBACf,IAAI;AAAA,gBACJ,UAAU,YAAY,GAAG;AAAA,gBACzB,OAAO;AAAA,kBACL;AAAA,kBACA,OAAO,QAAQ;AAAA,kBACf,aAAa,QAAQ;AAAA,kBACrB,OAAO,QAAQ;AAAA,kBACf,UAAU,IAAI;AAAA,gBAAA;AAAA,cAChB,CACD;AAAA,YAAA;AAGL,iBAAO;AAAA,QACT;AAAA,MAAA,CACD;AAAA,IACH,CAAC;AAAA,EAAA;AAEL,CAAC,EAAE,cAAc;AAAA,EACf,IAAI;AAAA,EACJ,SAAS,CAAC,EAAE,aAAa;AAAA,IACvB,UAAU,MAAM;AAAA,IAChB,8BAAc,IAAA;AAAA,EAAI;AAAA,EAEpB,IAAI;AAAA,IACF,iBAAiB,EAAE,SAAS,eAAA;AAAA,EAAe;AAE/C,CAAC,GC3FK,iCAAwD,UACxD,0BAAuC,SA+CvC,qBAAqB,CACzB,WACA,kBACiB,cAAc,WAAW,gBAAgB,WAUtD,qBAAqB,aAIzB,CAAC,EAAE,OAAO,SAAS,UAAU,cAAc;AAC3C,MAAI,CAAC,QAAS;AAEd,QAAM,kCAAkC,QAAQ;AAAA,IAC9C,CAAC,SAAS;AAIR,eAAS;AAAA,QACP,MAAM;AAAA,QACN,sBAAsB,QAAQ;AAAA,MAAA,CAC/B;AAAA,IACH;AAAA,EAAA,GAGI,gBAAgB,QAAQ,uBAAuB,CAAC,SAAS;AAC7D,aAAS,EAAE,MAAM,qBAAqB,eAAe,MAAM;AAAA,EAC7D,CAAC;AAED,SAAA,QAAQ,CAAC,UAAU;AAIb,YAAQ,8BAA8B,MAAM,wBAGhD,QAAQ,4BAA4B,MAAM,oBAAoB;AAAA,EAChE,CAAC,GAEM,MAAM;AACX,oCAAA,GACA,cAAA;AAAA,EACF;AACF,CAAC,GAKY,yBAAyB,MAAM;AAAA,EAC1C,OAAO;AAAA,IACL,OAAO,CAAA;AAAA,IACP,SAAS,CAAA;AAAA,IAGT,QAAQ,CAAA;AAAA,EAAC;AAAA,EAEX,QAAQ;AAAA,IACN,eAAe;AAAA,EAAA;AAAA,EAEjB,SAAS;AAAA,IACP,yBAAyB,OAAO;AAAA,MAC9B,sBAAsB,CACpB,GACA,WACG,OAAO;AAAA,MACZ,aAAa,CACX,EAAE,WACF,WAEA,mBAAmB,OAAO,sBAAsB,QAAQ,aAAa;AAAA,IAAA,CACxE;AAAA,IACD,kBAAkB,OAAO;AAAA,MACvB,eAAe,CAAC,GAAG,WACjB,OAAO;AAAA,MACT,aAAa,CAAC,EAAE,WAAW,WACzB,mBAAmB,QAAQ,sBAAsB,OAAO,aAAa;AAAA,IAAA,CACxE;AAAA,EAAA;AAEL,CAAC,EAAE,cAAc;AAAA,EACf,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,SAAS,CAAC,EAAE,YAAY;AACtB,UAAM,UAAU,MAAM,SAChB,uBACJ,SAAS,wBAAA,KAA6B,gCAClC,gBACJ,SAAS,iBAAA,KAAsB;AAEjC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,mBAAmB,sBAAsB,aAAa;AAAA,IAAA;AAAA,EAEvE;AAAA,EACA,QAAQ;AAAA,IACN,IAAI;AAAA,IACJ,KAAK;AAAA,IACL,OAAO,CAAC,EAAE,QAAA,MAAc,QAAQ;AAAA,EAAA;AAAA,EAElC,QAAQ;AAAA,IACN,OAAO;AAAA,MACL,IAAI;AAAA,QACF,4BAA4B;AAAA,UAC1B,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,QAAQ,CAAC,EAAE,aAAa;AAAA,gBACtB,sBAAsB,MAAM;AAAA,cAAA;AAAA,YAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,YAMF,OAAO,WAAW,CAAC,EAAE,MAAA,MAAY,KAAK;AAAA,UAAA;AAAA,QACxC;AAAA,QAEF,qBAAqB;AAAA,UACnB,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,QAAQ,CAAC,EAAE,aAAa;AAAA,gBACtB,eAAe,MAAM;AAAA,cAAA;AAAA,YACvB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEJ,CAAC,GCvLK,wBAAwB,cAKxB,oBAAoB,KAIpB,oBAAoB,YAGxB,OAAO,EAAE,OAAO,aAAa;AAC7B,MAAI;AAIF,WAAO,MAHQ,UAAU,MAAM,UAAU;AAAA,MACvC,YAAY;AAAA,IAAA,CACb,EACmB,QAAuB;AAAA,MACzC,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,IAAA,CACD;AAAA,EACH,QAAQ;AACN,WAAO,EAAE,QAAQ,eAAA;AAAA,EACnB;AACF,CAAC,GAYY,iBAAiB,MAAM;AAAA,EAClC,OAAO;AAAA,IACL,OAAO,CAAA;AAAA,IACP,SAAS,CAAA;AAAA,IACT,QAAQ,CAAA;AAAA,EAAC;AAAA,EAEX,QAAQ;AAAA,IACN,cAAc;AAAA,EAAA;AAAA,EAEhB,QAAQ;AAAA,IACN,kBAAkB,CAAC,GAAG,WACpB,OAAO,WAAW;AAAA,EAAA;AAAA,EAEtB,SAAS;AAAA,IACP,aAAa,OAAO;AAAA,MAClB,OAAO,CAAC,EAAE,cAAc;AACtB,cAAM,YAAY,gBAAA,GACZ,SAAS,UAAU,QAAQ,UAAU;AAAA,UACzC,YAAY;AAAA,QAAA,CACb,GACK,QAAQ,mBAA4C,WAAW;AAAA,UACnE,eAAe;AAAA,UACf,gBAAgB,MACd,OAAO,QAAmC;AAAA,YACxC,KAAK;AAAA,YACL,KAAK;AAAA,UAAA,CACN;AAAA,UACH,YAAY,CAAC,UACX,OAAO,QAAQ;AAAA,YACb,KAAK;AAAA,YACL,QAAQ;AAAA,YACR,MAAM,EAAE,MAAA;AAAA,YACR,KAAK;AAAA,UAAA,CACN;AAAA,UACH,YAAY,CAAC,UACP,OAAO,YAAc,MAChB,KAEF,UAAU;AAAA,YACf,OAAO,OAAO,eAAe;AAAA,YAC7B,KAAK,UAAU,EAAE,MAAA,CAAO;AAAA,UAAA;AAAA,QAC1B,CAEH;AACD,eAAA,MAAM,OAAO,qBAAqB,QAAQ,cAAc,GACjD;AAAA,MACT;AAAA,IAAA,CACD;AAAA,IACD,eAAe,CAAC,EAAE,cAAc;AAC9B,cAAQ,OAAO,IAAA;AAAA,IACjB;AAAA,EAAA;AAEJ,CAAC,EAAE,cAAc;AAAA,EACf,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,SAAS,CAAC,EAAE,aAAa;AAAA,IACvB,UAAU,MAAM;AAAA,IAChB,OAAO;AAAA,IACP,gBAAgB;AAAA,MACd,SAAS,MAAM;AAAA,MACf,gBAAgB,MAAM;AAAA,MACtB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,IAAA;AAAA,EACnB;AAAA,EAEF,QAAQ;AAAA,IACN,MAAM;AAAA,MACJ,IAAI;AAAA,QACF,mBAAmB;AAAA,UACjB,QAAQ;AAAA,QAAA;AAAA,MACV;AAAA,IACF;AAAA,IAEF,iBAAiB;AAAA,MACf,QAAQ;AAAA,QACN,KAAK;AAAA,QACL,OAAO,CAAC,EAAE,eAAe;AAAA,UACvB,UAAU,QAAQ;AAAA,QAAA;AAAA,QAEpB,QAAQ;AAAA,UACN;AAAA,YACE,OAAO;AAAA,cACL,MAAM;AAAA,cACN,QAAQ,CAAC,EAAE,aAAa;AAAA,gBACtB,QAAQ,MAAM,OAAO;AAAA,cAAA;AAAA,YACvB;AAAA,YAEF,SAAS,CAAC,EAAE,MAAM,eAAe;AAAA,YACjC,QAAQ;AAAA,UAAA;AAAA,UAEV;AAAA,YACE,QAAQ;AAAA,UAAA;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,IAEF,QAAQ;AAAA,MACN,MAAM,CAAC,oBAAoB;AAAA,MAC3B,MAAM,CAAC,EAAE,MAAM,iBAAiB;AAAA,MAChC,IAAI;AAAA,QACF,kBAAkB,EAAE,QAAQ,UAAA;AAAA,MAAU;AAAA,IACxC;AAAA,IAEF,SAAS;AAAA,MACP,MAAM;AAAA,IAAA;AAAA,IAER,QAAQ;AAAA,MACN,MAAM,CAAC,oBAAoB;AAAA,IAAA;AAAA,EAC7B;AAEJ,CAAC,GCtHY,KAAK,MAAM;AAAA,EACtB,OAAO;AAAA,IACL,OAAO,CAAA;AAAA,IACP,SAAS,CAAA;AAAA,IACT,QAAQ,CAAA;AAAA;AAAA,IAKR,UAAU,CAAA;AAAA,EAAC;AAAA,EAQb,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,SAAS;AAAA,IACT,UAAU;AAAA,EAAA;AAAA,EAEZ,QAAQ;AAAA,IACN,QAAQ,CAAC,GAAG,WAAgC,OAAO;AAAA,EAAA;AAAA,EAErD,SAAS;AAAA,IACP,gBAAgB,MAAM,EAAE,MAAM,mBAAmB;AAAA,IACjD,iBAAiB,MAAM,EAAE,MAAM,oBAAoB;AAAA,IACnD,qBAAqB,MAAM;AAAA,MACzB,MAAM;AAAA,IAAA,CACP;AAAA,IACD,gBAAgB,OAAO,aAAa;AAAA,MAClC,MAAM;AAAA,IAAA,CACP;AAAA,EAAA;AAEL,CAAC,EAAE,cAAc;AAAA,EACf,IAAI;AAAA,EACJ,SAAS,CAAC,EAAE,aAAa;AAAA,IACvB,UAAU,qBAAA;AAAA,IACV,oBAAoB,eAAe;AAAA,MACjC,MAAM;AAAA,MACN,SAAS,CAAC,IAAI,OAAO,KAAK,CAAC;AAAA,IAAA,CAC5B;AAAA,IACD,gBAAgB;AAAA,MACd,SAAS,MAAM;AAAA,MACf,gBAAgB,MAAM;AAAA,MACtB,aAAa,MAAM;AAAA,MACnB,WAAW,MAAM;AAAA,IAAA;AAAA,IAEnB,0BAA0B,MAAM;AAAA,EAAA;AAAA,EAElC,SAAS;AAAA,EACT,QAAQ;AAAA,IACN;AAAA,MACE,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO,CAAC,EAAE,QAAA,OAAe,EAAE,UAAU,QAAQ;MAC7C,YAAY;AAAA,QACV;AAAA,UACE,OAAO;AAAA,YACL,MAAM;AAAA,YACN,QAAQ,CAAC,EAAE,aAAa;AAAA,cACtB,QAAQ,MAAM,SAAS,OAAO,eAAe;AAAA,YAAA;AAAA,UAC/C;AAAA,UAEF,SAAS,CAAC,EAAE,MAAM,kBAAkB;AAAA,QAAA;AAAA,QAEtC;AAAA,UACE,OAAO;AAAA,YACL,MAAM;AAAA,YACN,QAAQ,CAAC,EAAE,aAAa;AAAA,cACtB,QAAQ,MAAM,SAAS,OAAO,OAAO;AAAA,YAAA;AAAA,UACvC;AAAA,UAEF,SAAS,CAAC,EAAE,MAAM,mBAAmB;AAAA,QAAA;AAAA,MACvC;AAAA,IACF;AAAA,IAEF;AAAA,MACE,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO,CAAC,EAAE,eAAe;AAAA,QACvB,UAAU,QAAQ;AAAA,QAClB,GAAG,QAAQ;AAAA,MAAA;AAAA,MAEb,YAAY;AAAA,QACV;AAAA,UACE,OAAO;AAAA,YACL,MAAM;AAAA,YACN,QAAQ,CAAC,EAAE,aAAa;AAAA,cACtB,QAAQ,MAAM,SAAS,OAAO,oBAAoB;AAAA,YAAA;AAAA,UACpD;AAAA,UAEF,SAAS,CAAC,EAAE,MAAM,uBAAuB;AAAA,QAAA;AAAA,MAC3C;AAAA,IACF;AAAA,IAEF;AAAA,MACE,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO,CAAC,EAAE,QAAA,OAAe,EAAE,SAAS,QAAQ,yBAAA;AAAA,IAAyB;AAAA,IAEvE;AAAA,MACE,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO,CAAC,EAAE,QAAA,OAAe,EAAE,UAAU,QAAQ,mBAAA;AAAA,IAAmB;AAAA,IAElE;AAAA,MACE,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO,CAAC,EAAE,QAAA,OAAe,EAAE,UAAU,QAAQ,mBAAA;AAAA,IAAmB;AAAA,EAClE;AAAA,EAEF,QAAQ;AAAA,IACN,SAAS;AAAA,MACP,SAAS;AAAA,MACT,QAAQ;AAAA,QACN,MAAM;AAAA,UACJ,IAAI;AAAA,YACF,mBAAmB;AAAA,cACjB,QAAQ;AAAA,cACR,SAAS,CAAC,EAAE,MAAM,kBAAkB;AAAA,YAAA;AAAA,YAEtC,oBAAoB,EAAE,QAAQ,QAAA;AAAA,UAAQ;AAAA,QACxC;AAAA,QAEF,WAAW;AAAA,UACT,IAAI;AAAA,YACF,wBAAwB,EAAE,QAAQ,OAAA;AAAA,UAAO;AAAA,QAC3C;AAAA,QAEF,OAAO,CAAA;AAAA,QACP,MAAM,EAAE,MAAM,QAAA;AAAA,MAAQ;AAAA,MAExB,QAAQ,EAAE,QAAQ,UAAA;AAAA,IAAU;AAAA,IAE9B,SAAS;AAAA,MACP,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ,CAAC;AAUM,SAAS,gBAAgB,OAAgB;AAC9C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,EAAA;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"system.js","sources":["../src/system/load-federated-module.ts","../src/system/remote.machine.ts","../src/system/auth.machine.ts","../src/system/inspect.ts","../src/system/remotes.machine.ts","../src/system/service.machine.ts","../src/system/services.machine.ts","../src/system/system-preferences.machine.ts","../src/system/telemetry.machine.ts","../src/system/root.machine.ts"],"sourcesContent":["import { logger } from \"../core/log\";\nimport type { FederationInstance } from \"./module-federation\";\n\n/**\n * A module exposed by an application's federation remote.\n *\n * @public\n */\nexport interface FederatedModuleRef {\n /**\n * Fully-qualified module id — `${appId}/${expose}`, e.g.\n * `studio-1/views/feed/panel` (a view component) or `studio-1/App` (the\n * full-page view). The remote's name is its first segment.\n */\n moduleId: string;\n /** The remote's `mf-manifest.json` URL (served from the app's origin). */\n entry: string;\n}\n\n/**\n * Register an app's federation remote (idempotent) and load one of its exposes\n * by its fully-qualified `moduleId`. Failures propagate, so the caller drives\n * its own error handling (e.g. a machine's error state with the original\n * cause). For the render-empty-on-failure policy, use {@link loadFederatedModule}.\n */\nexport async function loadRemoteModule<T>(\n instance: FederationInstance,\n { moduleId, entry }: FederatedModuleRef,\n): Promise<T | null> {\n // The remote name is the first segment; the expose is the remainder.\n const name = moduleId.slice(0, moduleId.indexOf(\"/\"));\n instance.registerRemotes([{ name, entry }]);\n return (await instance.loadRemote<T | null>(moduleId)) ?? null;\n}\n\n/**\n * {@link loadRemoteModule} with the render-empty-on-failure policy: any failure\n * resolves to `null` (and logs), so every caller handles a missing interface\n * the same way — a panel renders empty, a worker doesn't spawn.\n *\n * @public\n */\nexport async function loadFederatedModule<T>(\n instance: FederationInstance,\n ref: FederatedModuleRef,\n): Promise<T | null> {\n try {\n return await loadRemoteModule<T>(instance, ref);\n } catch (error) {\n logger.error(`Failed to load federated module \"${ref.moduleId}\"`, error);\n return null;\n }\n}\n","import { assign, fromPromise, sendParent, setup } from \"xstate\";\n\nimport { loadRemoteModule } from \"./load-federated-module\";\nimport type { FederationInstance } from \"./module-federation\";\n\n/**\n * @public\n */\nexport interface RemoteRenderOptions {\n basePath?: string;\n scheme?: \"light\" | \"dark\";\n /**\n * This is a temporary measure designed to authenticate federated\n * studios & SDK apps before we write a working protocol.\n */\n unstable_temporaryToken?: string | null;\n}\n\n/**\n * A loaded render-contract module. `TProps` is what its `render` accepts —\n * `RemoteRenderOptions` for an application's full-page view, the view's props\n * for a dock-panel component.\n * @public\n */\nexport interface LoadedRemoteModule<TProps = RemoteRenderOptions> {\n render: (rootElement: HTMLElement, props?: TProps) => () => void;\n}\n\n/**\n * A worker service's loader module — the `worker` interface's expose. Carries\n * the worker bundle URL (root-relative to the app origin) for the host to\n * bootstrap, not a render function; the services counterpart of\n * {@link LoadedRemoteModule}.\n * @public\n */\nexport interface ServiceLoaderModule {\n url: string;\n type: string;\n name: string;\n version: number;\n}\n\n/**\n * The federated-module shape each interface type exposes, keyed by\n * `interface_type`. Every interface — `panel`, `app`, `worker` — loads through\n * the same {@link remoteLogic} lifecycle; this maps what its loaded module looks\n * like so each consumer narrows the machine's shape-agnostic `module` to the\n * right type: a render contract for `panel`/`app` (rendered by an island), a\n * worker loader for `worker` (run as a Web Worker, never rendered).\n * @public\n */\nexport interface RemoteModuleByInterfaceType {\n panel: LoadedRemoteModule;\n app: LoadedRemoteModule;\n worker: ServiceLoaderModule;\n}\n\n/**\n * @public\n */\nexport interface RemoteError {\n message: string;\n cause: unknown;\n}\n\n/**\n * Thrown by a render consumer (e.g. the island) when a loaded module doesn't\n * expose a `render` function. Render-specific — `remoteLogic` itself is\n * shape-agnostic, so this lives with the consumer that needs the contract, not\n * the loader. Surfaced via `RemoteError.cause` for consumers that discriminate.\n * @public\n */\nexport class ModuleShapeError extends Error {\n constructor(remoteId: string) {\n super(`Remote \"${remoteId}\" did not expose a render function`);\n }\n}\n\n/**\n * Thrown by the load actor when a remote's expose resolves empty — the module\n * isn't published, or `loadRemote` returned nothing. Generic across interface\n * types; the shape-specific check (a render function, a worker URL) is the\n * consumer's, since `remoteLogic` loads every interface the same way.\n * @internal\n */\nexport class ModuleLoadError extends Error {\n constructor(remoteId: string) {\n super(`Remote module \"${remoteId}\" failed to load`);\n }\n}\n\n/**\n * @internal\n */\nexport interface RemoteInput {\n /** Fully-qualified module id — `${appId}/${expose}`. One child per moduleId. */\n moduleId: string;\n entry: string;\n instance: FederationInstance;\n}\n\ntype RemoteContext = RemoteInput & {\n /** The loaded module, shape-agnostic — each consumer narrows it. @see {@link RemoteModuleByInterfaceType} */\n module: unknown;\n error: RemoteError | null;\n};\n\nconst loadLogic = fromPromise<unknown, RemoteInput>(async ({ input }) => {\n const remoteModule = await loadRemoteModule<unknown>(input.instance, {\n moduleId: input.moduleId,\n entry: input.entry,\n });\n // The loader is interface-agnostic: it only guarantees a module came back.\n // Render-vs-worker shape validation is the consumer's (a panel/app island\n // checks `render`; a service checks `url`).\n if (remoteModule == null) {\n throw new ModuleLoadError(input.moduleId);\n }\n return remoteModule;\n});\n\n/**\n * Lifecycle machine for a single federated interface module — an application's\n * `App` entry, one view component, or a worker service's loader. Interface-\n * agnostic: it loads and tracks any module, leaving the shape contract\n * (render vs. worker URL) to the consumer.\n *\n * Spawned by the {@link remotesLogic} supervisor on demand, one per remote id\n * (`${appId}/${moduleId}`). Each instance owns one module's load lifecycle:\n * `loading` → `loaded | error`. Tags (`loading` / `ready` / `failed`) drive the\n * UI contract — state names are internal.\n *\n * The machine sends a `remote.settled` event to its parent on entry to\n * either terminal state, reserved for future supervision/retry.\n *\n * @internal\n */\nexport const remoteLogic = setup({\n types: {\n input: {} as RemoteInput,\n context: {} as RemoteContext,\n tags: {} as \"loading\" | \"ready\" | \"failed\",\n },\n actors: {\n load: loadLogic,\n },\n actions: {\n setModule: assign({\n module: (_, params: { module: unknown }) => params.module,\n error: () => null,\n }),\n setError: assign({\n module: () => null,\n error: (_, params: { error: unknown }) => normaliseError(params.error),\n }),\n },\n}).createMachine({\n id: \"remote\",\n initial: \"loading\",\n context: ({ input }) => ({\n ...input,\n module: null,\n error: null,\n }),\n states: {\n loading: {\n tags: [\"loading\"],\n invoke: {\n src: \"load\",\n input: ({ context }) => ({\n moduleId: context.moduleId,\n entry: context.entry,\n instance: context.instance,\n }),\n onDone: {\n target: \"loaded\",\n actions: [\n {\n type: \"setModule\",\n params: ({ event }) => ({ module: event.output }),\n },\n ],\n },\n onError: {\n target: \"error\",\n actions: [\n {\n type: \"setError\",\n params: ({ event }) => ({ error: event.error }),\n },\n ],\n },\n },\n },\n loaded: {\n tags: [\"ready\"],\n entry: sendParent(({ context }) => ({\n type: \"remote.settled\" as const,\n moduleId: context.moduleId,\n status: \"loaded\" as const,\n })),\n },\n error: {\n tags: [\"failed\"],\n entry: sendParent(({ context }) => ({\n type: \"remote.settled\" as const,\n moduleId: context.moduleId,\n status: \"error\" as const,\n })),\n },\n },\n});\n\nfunction normaliseError(error: unknown): RemoteError {\n if (error instanceof Error) {\n return { message: error.message, cause: error };\n }\n return { message: String(error), cause: error };\n}\n","import {\n type AuthState,\n AuthStateType,\n type CurrentUser,\n getAuthState,\n type LoggedInAuthState,\n logout,\n type SanityInstance,\n} from \"@sanity/sdk\";\nimport { assign, fromObservable, fromPromise, setup } from \"xstate\";\n\nimport type { OSBaseInput } from \"./root.machine\";\n\n/**\n * @internal\n */\nexport interface AuthInput extends OSBaseInput {}\n\nconst authStateLogic = fromObservable<AuthState, AuthInput>(\n ({ input }) => getAuthState(input.instance).observable,\n);\n\n/**\n * @internal\n */\nexport interface LogoutInput extends OSBaseInput {}\n\nconst logoutActorLogic = fromPromise<void, LogoutInput>(async ({ input }) => {\n await logout(input.instance);\n});\n\ntype AuthContext = {\n instance: SanityInstance;\n token: string | null;\n currentUser: CurrentUser | null;\n error: unknown;\n};\n\ntype AuthEvent = { type: \"auth.logout\" };\n\nexport const authLogic = setup({\n types: {\n input: {} as AuthInput,\n context: {} as AuthContext,\n events: {} as AuthEvent,\n tags: {} as \"authenticating\" | \"authenticated\" | \"error\",\n },\n actors: {\n authState: authStateLogic,\n logoutActor: logoutActorLogic,\n },\n delays: {\n authTimeout: 30_000,\n },\n guards: {\n isLoggedInComplete: (_, params: { state: AuthState | undefined }) =>\n params.state?.type === AuthStateType.LOGGED_IN &&\n Boolean((params.state as LoggedInAuthState).token) &&\n (params.state as LoggedInAuthState).currentUser !== null,\n isAuthState: (\n _,\n params: { state: AuthState | undefined; type: AuthStateType },\n ) => params.state?.type === params.type,\n },\n actions: {\n setLoggedIn: assign({\n token: (_, params: { token: string; currentUser: CurrentUser }) =>\n params.token,\n currentUser: (_, params: { token: string; currentUser: CurrentUser }) =>\n params.currentUser,\n error: () => null,\n }),\n clearAuth: assign({\n token: () => null,\n currentUser: () => null,\n error: () => null,\n }),\n setError: assign({\n token: () => null,\n currentUser: () => null,\n error: (_, params: { error: unknown }) => params.error,\n }),\n },\n}).createMachine({\n id: \"auth\",\n initial: \"init\",\n context: ({ input }) => ({\n instance: input.instance,\n token: null,\n currentUser: null,\n error: null,\n }),\n invoke: {\n src: \"authState\",\n input: ({ context }) => ({ instance: context.instance }),\n onSnapshot: [\n {\n guard: {\n type: \"isLoggedInComplete\",\n params: ({ event }) => ({\n state: event.snapshot.context,\n }),\n },\n actions: [\n {\n type: \"setLoggedIn\",\n params: ({ event }) => {\n const state = event.snapshot.context as LoggedInAuthState;\n return {\n token: state.token,\n currentUser: state.currentUser!,\n };\n },\n },\n ],\n target: `.${AuthStateType.LOGGED_IN}`,\n },\n {\n guard: {\n type: \"isAuthState\",\n params: ({ event }) => ({\n state: event.snapshot.context,\n type: AuthStateType.LOGGING_IN,\n }),\n },\n actions: [{ type: \"clearAuth\" }],\n target: `.${AuthStateType.LOGGING_IN}`,\n },\n {\n guard: {\n type: \"isAuthState\",\n params: ({ event }) => ({\n state: event.snapshot.context,\n type: AuthStateType.ERROR,\n }),\n },\n actions: [\n {\n type: \"setError\",\n params: ({ event }) => ({\n error:\n event.snapshot.context?.type === AuthStateType.ERROR\n ? event.snapshot.context.error\n : null,\n }),\n },\n ],\n target: `.${AuthStateType.ERROR}`,\n },\n {\n guard: {\n type: \"isAuthState\",\n params: ({ event }) => ({\n state: event.snapshot.context,\n type: AuthStateType.LOGGED_OUT,\n }),\n },\n actions: [{ type: \"clearAuth\" }],\n target: `.${AuthStateType.LOGGED_OUT}`,\n },\n ],\n },\n states: {\n init: {\n tags: [\"authenticating\"],\n after: {\n authTimeout: {\n actions: [\n {\n type: \"setError\",\n params: () => ({\n error: new Error(\"Authentication timed out\"),\n }),\n },\n ],\n target: AuthStateType.ERROR,\n },\n },\n },\n [AuthStateType.LOGGING_IN]: {\n tags: [\"authenticating\"],\n after: {\n authTimeout: {\n actions: [\n {\n type: \"setError\",\n params: () => ({\n error: new Error(\"Authentication timed out\"),\n }),\n },\n ],\n target: AuthStateType.ERROR,\n },\n },\n },\n [AuthStateType.LOGGED_IN]: {\n tags: [\"authenticated\"],\n on: {\n \"auth.logout\": { target: \"logging-out\" },\n },\n },\n [\"logging-out\"]: {\n invoke: {\n src: \"logoutActor\",\n input: ({ context }) => ({ instance: context.instance }),\n onDone: {\n target: AuthStateType.LOGGED_OUT,\n },\n onError: {\n actions: [\n {\n type: \"setError\",\n params: ({ event }) => ({ error: event.error }),\n },\n ],\n target: AuthStateType.ERROR,\n },\n },\n },\n [AuthStateType.LOGGED_OUT]: {},\n [AuthStateType.ERROR]: { tags: [\"error\"] },\n },\n});\n","import { type ActorRefLike, type InspectionEvent } from \"xstate\";\n\nimport { logger } from \"../core\";\n\n// Mirrors @statelyai/inspect's ActorRefLikeWithData — the inspect\n// callback receives full Actor instances at runtime, but the type is\n// narrowed for @xstate/store compat.\ntype ActorRefWithAncestry = ActorRefLike & {\n id?: string;\n _parent?: ActorRefWithAncestry;\n};\n\nconst actorPath = (ref: ActorRefWithAncestry): string => {\n const segments: string[] = [];\n let current: ActorRefWithAncestry | undefined = ref;\n while (current) {\n segments.unshift(current.id ?? current.sessionId);\n current = current._parent;\n }\n return segments.join(\":\");\n};\n\n/** @internal exported for testing */\nexport const inspect = (event: InspectionEvent): void => {\n const ref = event.actorRef as ActorRefWithAncestry;\n const log = logger.child(actorPath(ref));\n\n switch (event.type) {\n case \"@xstate.snapshot\": {\n log.debug(\"snapshot\", event.snapshot);\n break;\n }\n case \"@xstate.event\":\n log.debug(\"event\", event.event);\n break;\n case \"@xstate.action\":\n log.debug(\"action\", event.action);\n break;\n }\n};\n","import { type ActorRefFrom, assign, setup } from \"xstate\";\n\nimport { type FederationInstance } from \"./module-federation\";\nimport { remoteLogic } from \"./remote.machine\";\n\n/** The shared federation instance, supplied by the root machine. */\ntype RemotesInput = {\n instance: FederationInstance;\n};\n\ntype RemotesContext = {\n instance: FederationInstance;\n children: Map<string, ActorRefFrom<typeof remoteLogic>>;\n};\n\ntype RemotesEvent =\n | { type: \"remote.load.request\"; moduleId: string; entry: string }\n | { type: \"remote.settled\"; moduleId: string; status: \"loaded\" | \"error\" };\n\n/**\n * Supervisor machine for federated modules.\n *\n * Uses the shared {@link FederationInstance} (the `workbench-applications`\n * instance, supplied by the root machine and shared with `services`) and spawns\n * one {@link remoteLogic} child per remote id (`${appId}/${moduleId}`) — so an\n * application's `App` entry and each of its dock-panel view components load (and\n * are tracked) independently. The\n * supervisor is invoked at the root of the OS machine for inspector visibility\n * (`[sanity-workbench:os:remotes]`) — boot does not gate on it.\n *\n * @internal\n */\nexport const remotesLogic = setup({\n types: {\n input: {} as RemotesInput,\n context: {} as RemotesContext,\n events: {} as RemotesEvent,\n },\n actors: {\n remote: remoteLogic,\n },\n guards: {\n remoteNotKnown: ({ context }, params: { moduleId: string }) =>\n !context.children.has(params.moduleId),\n },\n actions: {\n spawnRemote: assign({\n children: (\n { context, spawn },\n params: { moduleId: string; entry: string },\n ) => {\n const ref = spawn(\"remote\", {\n id: params.moduleId,\n systemId: `remotes.${params.moduleId}`,\n input: {\n moduleId: params.moduleId,\n entry: params.entry,\n instance: context.instance,\n },\n });\n return new Map(context.children).set(params.moduleId, ref);\n },\n }),\n },\n}).createMachine({\n id: \"remotes\",\n context: ({ input }) => ({\n instance: input.instance,\n children: new Map(),\n }),\n on: {\n \"remote.load.request\": {\n guard: {\n type: \"remoteNotKnown\",\n params: ({ event }) => ({ moduleId: event.moduleId }),\n },\n actions: [\n {\n type: \"spawnRemote\",\n params: ({ event }) => ({\n moduleId: event.moduleId,\n entry: event.entry,\n }),\n },\n ],\n },\n // Reserved for future supervision/retry. Forwarded by per-remote\n // children on entry to `loaded` or `error`; currently a no-op so the\n // event is part of the typed surface rather than a silent unknown.\n \"remote.settled\": {},\n },\n});\n","import { assign, fromCallback, setup } from \"xstate\";\n\nimport { logger } from \"../core/log\";\nimport { type FederationInstance } from \"./module-federation\";\nimport {\n remoteLogic,\n type RemoteError,\n type ServiceLoaderModule,\n} from \"./remote.machine\";\n\n/**\n * @internal\n */\nexport interface ServiceInput {\n /** Stable child key, `${appId}:${serviceName}`. */\n key: string;\n appId: string;\n serviceName: string;\n /** The app's `mf-manifest.json` URL — the federation remote entry. */\n entry: string;\n instance: FederationInstance;\n}\n\ntype ServiceContext = ServiceInput & {\n /** Resolved worker-bundle URL, absolute on the app origin. */\n workerUrl: string | null;\n};\n\n/** Federation expose segment a service's loader lives under: `services/<name>`. */\nconst SERVICES_MODULE = \"services\";\n\n/**\n * Run the worker. `new Worker(appOriginUrl)` is cross-origin-blocked, and the\n * dev worker isn't self-contained (its root-relative imports would resolve\n * against the wrong origin from a blob). So bootstrap a same-origin worker that\n * dynamically `import()`s the app-origin URL: the worker module then resolves\n * its own imports against the app origin, in dev and build alike. Crashes, a\n * failed load, and the worker's `console.*` (bridged by the wrapper) are\n * surfaced through the host logger (the host owns logging; a worker's own\n * console isn't visible in the page DevTools anyway). Cleanup disposes, then\n * terminates.\n */\nconst runWorker = fromCallback<\n { type: string },\n { key: string; serviceName: string; workerUrl: string }\n>(({ input }) => {\n let worker: Worker | undefined;\n let blobUrl: string | undefined;\n\n try {\n // A same-origin module worker whose only job is to load the real worker\n // from the app origin, so that worker's imports resolve there too.\n const bootstrap = `import(${JSON.stringify(input.workerUrl)})`;\n blobUrl = URL.createObjectURL(\n new Blob([bootstrap], { type: \"text/javascript\" }),\n );\n worker = new Worker(blobUrl, { type: \"module\" });\n\n worker.addEventListener(\"message\", (event: MessageEvent) => {\n if (event.data?.kind === \"workbench.worker.error\") {\n logger.error(\n `Service \"${input.key}\" worker error`,\n event.data.payload?.message,\n );\n } else if (event.data?.kind === \"workbench.worker.log\") {\n // Re-emit the worker's `console.*` (bridged by the wrapper) through the\n // host logger, prefixed with the service name so it shows in the page\n // console.\n const { level, message } = event.data.payload ?? {};\n const emit: Record<string, (message: string) => void> = {\n warn: logger.warn,\n error: logger.error,\n debug: logger.debug,\n };\n (emit[level] ?? logger.info)(\n `[service:${input.serviceName}] ${message ?? \"\"}`,\n );\n }\n });\n\n // A module-load failure (or any uncaught worker error) fires here on the\n // host side — surface it instead of failing silently.\n worker.addEventListener(\"error\", (event: ErrorEvent) => {\n logger.error(\n `Service \"${input.key}\" worker error: ${event.message || String(event)}`,\n );\n });\n } catch (error) {\n logger.error(`Service \"${input.key}\" failed to start its worker`, error);\n }\n\n return () => {\n try {\n worker?.postMessage({ kind: \"workbench.worker.terminate\" });\n } finally {\n worker?.terminate();\n if (blobUrl) URL.revokeObjectURL(blobUrl);\n }\n };\n});\n\n/**\n * Lifecycle machine for a single background service worker.\n *\n * Spawned by the {@link servicesLogic} supervisor, one per `(app, service)`.\n * `loading` loads the worker's loader module through the shared\n * {@link remoteLogic} lifecycle — the same machine every interface (panel, app,\n * worker) loads through — and reads the bundle URL off it. A worker isn't a\n * render module, so it's never handed to an island; `running` bootstraps it as\n * a Web Worker from that URL.\n *\n * @internal\n */\nexport const serviceLogic = setup({\n types: {\n input: {} as ServiceInput,\n context: {} as ServiceContext,\n tags: {} as \"loading\" | \"running\" | \"failed\",\n },\n actors: {\n loadInterface: remoteLogic,\n runWorker,\n },\n}).createMachine({\n id: \"service\",\n initial: \"loading\",\n context: ({ input }) => ({ ...input, workerUrl: null }),\n // The invoked loader `sendParent`s a `remote.settled` on settle; this machine\n // reacts via `onSnapshot` instead, so the event is a no-op here.\n on: { \"remote.settled\": {} },\n states: {\n loading: {\n tags: [\"loading\"],\n invoke: {\n id: \"loader\",\n src: \"loadInterface\",\n input: ({ context }) => ({\n moduleId: `${context.appId}/${SERVICES_MODULE}/${context.serviceName}`,\n entry: context.entry,\n instance: context.instance,\n }),\n onSnapshot: [\n {\n // Loaded and exposing a bundle URL → run it.\n guard: ({ event }) => {\n const module = event.snapshot.context\n .module as ServiceLoaderModule | null;\n return (\n event.snapshot.hasTag(\"ready\") &&\n typeof module?.url === \"string\"\n );\n },\n target: \"running\",\n actions: assign({\n workerUrl: ({ context, event }) => {\n const module = event.snapshot.context\n .module as ServiceLoaderModule;\n // The URL is root-relative to the app; resolve it absolute\n // against the app origin since the loader runs in the host page.\n return new URL(module.url, new URL(context.entry).origin).href;\n },\n }),\n },\n {\n // Load failed, or loaded without a usable URL → no worker.\n guard: ({ event }) => {\n const module = event.snapshot.context\n .module as ServiceLoaderModule | null;\n return (\n event.snapshot.hasTag(\"failed\") ||\n (event.snapshot.hasTag(\"ready\") &&\n typeof module?.url !== \"string\")\n );\n },\n target: \"error\",\n // A worker has no UI surface (unlike a view's error boundary), so a\n // failed load would otherwise be silent — log it through the host.\n actions: ({ context, event }) => {\n const cause = (event.snapshot.context.error as RemoteError | null)\n ?.message;\n logger.error(\n `Service \"${context.key}\" failed to load its worker${\n cause ? `: ${cause}` : \"\"\n }`,\n );\n },\n },\n ],\n },\n },\n running: {\n tags: [\"running\"],\n invoke: {\n src: \"runWorker\",\n input: ({ context }) => ({\n key: context.key,\n serviceName: context.serviceName,\n // `workerUrl` is set on entry to `running` from `loading`'s output.\n workerUrl: context.workerUrl!,\n }),\n },\n },\n error: {\n tags: [\"failed\"],\n },\n },\n});\n","import { type ActorRefFrom, enqueueActions, setup } from \"xstate\";\n\nimport { type FederationInstance } from \"./module-federation\";\nimport { serviceLogic } from \"./service.machine\";\n\n/** The shared federation instance, supplied by the root machine. */\ntype ServicesInput = {\n instance: FederationInstance;\n};\n\ntype ServicesContext = {\n instance: FederationInstance;\n children: Map<string, ActorRefFrom<typeof serviceLogic>>;\n};\n\n/**\n * The full set of background services the workbench should currently be\n * running, re-sent whenever the application list — or any app's declared\n * interfaces — changes. The supervisor reconciles its children against it.\n */\ntype ServicesEvent = {\n type: \"services.sync\";\n services: ReadonlyArray<{\n appId: string;\n serviceName: string;\n entry: string;\n }>;\n};\n\n/** Stable child key for a service: `${appId}:${serviceName}`. */\nfunction serviceKey(appId: string, serviceName: string): string {\n return `${appId}:${serviceName}`;\n}\n\n/**\n * Supervisor machine for background service workers.\n *\n * Uses the shared {@link FederationInstance} (supplied by the root machine and\n * shared with `remotes`, so an app's remote is registered once for both its\n * views and its workers) and spawns one {@link serviceLogic} child per\n * `(app, service)`. Invoked at the root of the OS machine for inspector\n * visibility — boot does not gate on it.\n *\n * On every `services.sync` it reconciles its children against the desired set:\n * a newly-declared worker is spawned, and a worker whose declaration was\n * removed (e.g. deleted from `sanity.cli.ts` during dev — FR-024) is stopped,\n * which disposes its `runWorker` callback and terminates the Web Worker. A\n * service `src` edit still triggers a Vite full page reload (workers have no\n * HMR boundary), which reboots the workbench and respawns with the new code.\n *\n * @internal\n */\nexport const servicesLogic = setup({\n types: {\n input: {} as ServicesInput,\n context: {} as ServicesContext,\n events: {} as ServicesEvent,\n },\n actors: {\n service: serviceLogic,\n },\n actions: {\n /**\n * Reconcile the running workers against the desired set: spawn the ones not\n * yet running, stop (and forget) the ones no longer declared.\n */\n syncServices: enqueueActions(({ context, event, enqueue }) => {\n const desired = new Map(\n event.services.map((service) => [\n serviceKey(service.appId, service.serviceName),\n service,\n ]),\n );\n\n // Stop + forget workers whose declaration was removed. Stopping the child\n // disposes its `runWorker` callback, which terminates the Web Worker.\n for (const [key, ref] of context.children) {\n if (!desired.has(key)) enqueue.stopChild(ref);\n }\n\n enqueue.assign({\n children: ({ context: ctx, spawn }) => {\n const next = new Map<string, ActorRefFrom<typeof serviceLogic>>();\n // Keep the children still declared.\n for (const [key, ref] of ctx.children) {\n if (desired.has(key)) next.set(key, ref);\n }\n // Spawn the newly-declared ones.\n for (const [key, service] of desired) {\n if (next.has(key)) continue;\n next.set(\n key,\n spawn(\"service\", {\n id: key,\n systemId: `services.${key}`,\n input: {\n key,\n appId: service.appId,\n serviceName: service.serviceName,\n entry: service.entry,\n instance: ctx.instance,\n },\n }),\n );\n }\n return next;\n },\n });\n }),\n },\n}).createMachine({\n id: \"services\",\n context: ({ input }) => ({\n instance: input.instance,\n children: new Map(),\n }),\n on: {\n \"services.sync\": { actions: \"syncServices\" },\n },\n});\n","import { assign, fromCallback, sendTo, setup } from \"xstate\";\n\ntype ColorScheme = \"light\" | \"dark\";\n\ntype ColorSchemePreference = \"system\" | ColorScheme;\n\n/**\n * The system-preferences machine's context. Consumers read fields directly\n * (e.g. via `useSelector`) rather than going through a resolver utility —\n * the action handlers keep `colorScheme` in sync with `preferredColorScheme`\n * and `osColorScheme`.\n *\n * Note: `colorScheme` is intentionally stored as derived state in context so\n * consumers can read the resolved value directly without a utility. The\n * action handlers below are the single source of truth for the resolution.\n * @public\n */\nexport type SystemPreferencesContext = {\n /** User's color scheme choice; `system` defers to the OS preference. */\n preferredColorScheme: ColorSchemePreference;\n /** Last reported OS color scheme. Used to resolve `colorScheme` when the\n * preference is `system`. */\n osColorScheme: ColorScheme;\n /** Resolved color scheme — what the UI should render. Recomputed by the\n * action handlers whenever an input changes. */\n colorScheme: ColorScheme;\n};\n\nconst DEFAULT_PREFERRED_COLOR_SCHEME: ColorSchemePreference = \"system\";\nconst DEFAULT_OS_COLOR_SCHEME: ColorScheme = \"light\";\n\n/**\n * Events the system-preferences machine accepts. Both originate from the\n * host's adapter — `preferredColorScheme.set` is also forwarded back to it\n * so it can persist the user's choice.\n * @public\n */\nexport type SystemPreferencesEvent =\n | {\n type: \"preferredColorScheme.set\";\n preferredColorScheme: ColorSchemePreference;\n }\n | {\n type: \"osColorScheme.set\";\n osColorScheme: ColorScheme;\n };\n\n/**\n * Adapter interface the host implements to give the system-preferences\n * machine access to the user's environment (OS color scheme, persistent\n * storage, cross-context change notifications).\n *\n * The package owns all orchestration — synchronous seeding, idempotent\n * persistence, mapping cleared storage to `\"system\"`. The host's\n * implementation is pure DOM/storage glue: read, write, subscribe.\n * @public\n */\nexport type SystemPreferencesAdapter = {\n /** Read the user's stored preference. `null` means \"no preference set\"\n * (the machine treats this as `\"system\"`). */\n getPreferredColorScheme: () => ColorSchemePreference | null;\n /** Write the user's preference to persistent storage. */\n persistPreferredColorScheme: (value: ColorSchemePreference) => void;\n /** Subscribe to cross-context preference changes (e.g. another tab\n * writing to the shared storage). The callback receives the new stored\n * value (or `null` if it was cleared). Returns an unsubscribe function. */\n subscribePreferredColorScheme: (\n callback: (next: ColorSchemePreference | null) => void,\n ) => () => void;\n /** Read the current OS-detected color scheme. */\n getOsColorScheme: () => ColorScheme;\n /** Subscribe to OS color-scheme changes (e.g. user flipping dark mode).\n * Returns an unsubscribe function. */\n subscribeOsColorScheme: (callback: (next: ColorScheme) => void) => () => void;\n};\n\nconst resolveColorScheme = (\n preferred: ColorSchemePreference,\n osColorScheme: ColorScheme,\n): ColorScheme => (preferred === \"system\" ? osColorScheme : preferred);\n\n// Internal bridge actor — subscribes to the host's adapter for runtime\n// changes and persists user-driven preference changes when the parent\n// forwards them. No-op if the host didn't pass an adapter (SSR, tests).\ntype AdapterBridgeReceiveEvent = Extract<\n SystemPreferencesEvent,\n { type: \"preferredColorScheme.set\" }\n>;\n\nconst adapterBridgeLogic = fromCallback<\n AdapterBridgeReceiveEvent,\n SystemPreferencesAdapter | undefined,\n SystemPreferencesEvent\n>(({ input: adapter, sendBack, receive }) => {\n if (!adapter) return;\n\n const unsubscribePreferredColorScheme = adapter.subscribePreferredColorScheme(\n (next) => {\n // Falls back to `\"system\"` so an external clear (another tab deleting\n // the key) resets the preference rather than silently keeping the\n // previous value.\n sendBack({\n type: \"preferredColorScheme.set\",\n preferredColorScheme: next ?? \"system\",\n });\n },\n );\n\n const unsubscribeOs = adapter.subscribeOsColorScheme((next) => {\n sendBack({ type: \"osColorScheme.set\", osColorScheme: next });\n });\n\n receive((event) => {\n // Idempotent: skip writes that match the current stored value so a\n // `preferredColorScheme.set` originating from cross-context change\n // doesn't loop back into another write.\n if (adapter.getPreferredColorScheme() === event.preferredColorScheme)\n return;\n\n adapter.persistPreferredColorScheme(event.preferredColorScheme);\n });\n\n return () => {\n unsubscribePreferredColorScheme();\n unsubscribeOs();\n };\n});\n\n/**\n * @internal\n */\nexport const systemPreferencesLogic = setup({\n types: {\n input: {} as { adapter?: SystemPreferencesAdapter },\n context: {} as SystemPreferencesContext & {\n adapter: SystemPreferencesAdapter | undefined;\n },\n events: {} as SystemPreferencesEvent,\n },\n actors: {\n adapterBridge: adapterBridgeLogic,\n },\n actions: {\n setPreferredColorScheme: assign({\n preferredColorScheme: (\n _,\n params: { preferredColorScheme: ColorSchemePreference },\n ) => params.preferredColorScheme,\n colorScheme: (\n { context },\n params: { preferredColorScheme: ColorSchemePreference },\n ) =>\n resolveColorScheme(params.preferredColorScheme, context.osColorScheme),\n }),\n setOsColorScheme: assign({\n osColorScheme: (_, params: { osColorScheme: ColorScheme }) =>\n params.osColorScheme,\n colorScheme: ({ context }, params: { osColorScheme: ColorScheme }) =>\n resolveColorScheme(context.preferredColorScheme, params.osColorScheme),\n }),\n },\n}).createMachine({\n id: \"system-preferences\",\n initial: \"ready\",\n context: ({ input }) => {\n const adapter = input.adapter;\n const preferredColorScheme =\n adapter?.getPreferredColorScheme() ?? DEFAULT_PREFERRED_COLOR_SCHEME;\n const osColorScheme =\n adapter?.getOsColorScheme() ?? DEFAULT_OS_COLOR_SCHEME;\n\n return {\n adapter,\n preferredColorScheme,\n osColorScheme,\n colorScheme: resolveColorScheme(preferredColorScheme, osColorScheme),\n };\n },\n invoke: {\n id: \"adapter\",\n src: \"adapterBridge\",\n input: ({ context }) => context.adapter,\n },\n states: {\n ready: {\n on: {\n \"preferredColorScheme.set\": {\n actions: [\n {\n type: \"setPreferredColorScheme\",\n params: ({ event }) => ({\n preferredColorScheme: event.preferredColorScheme,\n }),\n },\n // Forward to the adapter bridge so it can persist the user's\n // choice. The bridge guards against redundant writes, so\n // round-tripping a `preferredColorScheme.set` it sourced itself\n // (e.g. from a `storage` event in another tab) is a no-op.\n sendTo(\"adapter\", ({ event }) => event),\n ],\n },\n \"osColorScheme.set\": {\n actions: [\n {\n type: \"setOsColorScheme\",\n params: ({ event }) => ({\n osColorScheme: event.osColorScheme,\n }),\n },\n ],\n },\n },\n },\n },\n});\n","import { getClient, type SanityInstance } from \"@sanity/sdk\";\nimport {\n type ConsentStatus,\n createBatchedStore,\n createSessionId,\n type TelemetryEvent,\n type TelemetryStore,\n} from \"@sanity/telemetry\";\nimport { assign, fromPromise, setup } from \"xstate\";\n\nimport type { OSBaseInput } from \"./root.machine\";\n\n/**\n * @public\n */\nexport type WorkbenchUserProperties = {\n version: string;\n organizationId: string;\n environment: string;\n userAgent: string;\n};\n\n/**\n * @internal\n */\nexport interface TelemetryInput extends OSBaseInput, WorkbenchUserProperties {}\n\n/**\n * TODO: this shouldn't be unique to the telemetry machine,\n * remove this and set it globally with a single client actor.\n */\nconst TELEMETRY_API_VERSION = \"2024-11-12\";\n/**\n * 30 seconds, in milliseconds, is the default flush interval\n * for the telemetry store.\n */\nconst FLUSH_INTERVAL_MS = 30_000;\n\ntype ConsentResult = { status: ConsentStatus };\n\nconst checkConsentLogic = fromPromise<\n ConsentResult,\n { instance: SanityInstance }\n>(async ({ input, signal }) => {\n try {\n const client = getClient(input.instance, {\n apiVersion: TELEMETRY_API_VERSION,\n });\n return await client.request<ConsentResult>({\n uri: \"/intake/telemetry-status\",\n tag: \"telemetry-consent\",\n signal,\n });\n } catch {\n return { status: \"undetermined\" } satisfies ConsentResult;\n }\n});\n\ntype TelemetryContext = {\n instance: SanityInstance;\n store: TelemetryStore<WorkbenchUserProperties> | null;\n userProperties: WorkbenchUserProperties;\n};\n\ntype TelemetryMachineEvent =\n | { type: \"telemetry.start\" }\n | { type: \"telemetry.stop\" };\n\nexport const telemetryLogic = setup({\n types: {\n input: {} as TelemetryInput,\n context: {} as TelemetryContext,\n events: {} as TelemetryMachineEvent,\n },\n actors: {\n checkConsent: checkConsentLogic,\n },\n guards: {\n isConsentGranted: (_, params: { status: ConsentStatus }) =>\n params.status === \"granted\",\n },\n actions: {\n createStore: assign({\n store: ({ context }) => {\n const sessionId = createSessionId();\n const client = getClient(context.instance, {\n apiVersion: TELEMETRY_API_VERSION,\n });\n const store = createBatchedStore<WorkbenchUserProperties>(sessionId, {\n flushInterval: FLUSH_INTERVAL_MS,\n resolveConsent: () =>\n client.request<{ status: ConsentStatus }>({\n uri: \"/intake/telemetry-status\",\n tag: \"telemetry-consent\",\n }),\n sendEvents: (batch: TelemetryEvent[]) =>\n client.request({\n uri: \"/intake/batch\",\n method: \"POST\",\n body: { batch },\n tag: \"telemetry.batch\",\n }),\n sendBeacon: (batch: TelemetryEvent[]) => {\n if (typeof navigator === \"undefined\") {\n return false;\n }\n return navigator.sendBeacon(\n client.getUrl(\"/intake/batch\"),\n JSON.stringify({ batch }),\n );\n },\n });\n store.logger.updateUserProperties(context.userProperties);\n return store;\n },\n }),\n teardownStore: ({ context }) => {\n context.store?.end();\n },\n },\n}).createMachine({\n id: \"telemetry\",\n initial: \"idle\",\n context: ({ input }) => ({\n instance: input.instance,\n store: null,\n userProperties: {\n version: input.version,\n organizationId: input.organizationId,\n environment: input.environment,\n userAgent: input.userAgent,\n },\n }),\n states: {\n idle: {\n on: {\n \"telemetry.start\": {\n target: \"checkingConsent\",\n },\n },\n },\n checkingConsent: {\n invoke: {\n src: \"checkConsent\",\n input: ({ context }) => ({\n instance: context.instance,\n }),\n onDone: [\n {\n guard: {\n type: \"isConsentGranted\",\n params: ({ event }) => ({\n status: event.output.status,\n }),\n },\n actions: [{ type: \"createStore\" }],\n target: \"active\",\n },\n {\n target: \"denied\",\n },\n ],\n },\n },\n active: {\n tags: [\"telemetry-resolved\"],\n exit: [{ type: \"teardownStore\" }],\n on: {\n \"telemetry.stop\": { target: \"stopped\" },\n },\n },\n stopped: {\n type: \"final\",\n },\n denied: {\n tags: [\"telemetry-resolved\"],\n },\n },\n});\n","import { createSanityInstance, type SanityInstance } from \"@sanity/sdk\";\nimport { raise, sendTo, setup, type ActorOptions } from \"xstate\";\n\nimport { logger } from \"../core/log\";\nimport { authLogic } from \"./auth.machine\";\nimport { inspect } from \"./inspect\";\nimport {\n createInstance,\n type FederationInstance,\n log,\n} from \"./module-federation\";\nimport { remotesLogic } from \"./remotes.machine\";\nimport { servicesLogic } from \"./services.machine\";\nimport {\n type SystemPreferencesAdapter,\n systemPreferencesLogic,\n} from \"./system-preferences.machine\";\nimport {\n telemetryLogic,\n type WorkbenchUserProperties,\n} from \"./telemetry.machine\";\n\ntype OSInput = WorkbenchUserProperties & {\n systemPreferencesAdapter?: SystemPreferencesAdapter;\n};\n\ntype OSContext = {\n instance: SanityInstance;\n /**\n * The single module-federation instance every interface loads through —\n * shared by the `remotes` (views) and `services` (workers) supervisors so an\n * app's remote is registered once for all its interfaces.\n */\n federationInstance: FederationInstance;\n userProperties: WorkbenchUserProperties;\n systemPreferencesAdapter: SystemPreferencesAdapter | undefined;\n};\n\n/**\n * The base inputs for the OS machine.\n * @internal\n */\nexport interface OSBaseInput extends Pick<OSContext, \"instance\"> {}\n\n/**\n * The sanity OS machine, responsible for managing the global state of the OS.\n * @public\n * @example\n * ```ts\n * import { os, createOSOptions } from \"@sanity/workbench/system\";\n * import { useActor } from \"@xstate/react\";\n *\n * const [state, send] = useActor(os, createOSOptions({\n * version: \"1.0.0\",\n * organizationId: \"...\",\n * environment: \"production\",\n * userAgent: navigator.userAgent,\n * }));\n * ```\n */\nexport const os = setup({\n types: {\n input: {} as OSInput,\n context: {} as OSContext,\n events: {} as\n | { type: \"boot.auth.ready\" }\n | { type: \"boot.auth.failed\" }\n | { type: \"boot.telemetry.ready\" },\n // https://github.com/statelyai/xstate/issues/5515\n children: {} as {\n auth: \"auth\";\n telemetry: \"telemetry\";\n \"system-preferences\": \"systemPreferences\";\n remotes: \"remotes\";\n services: \"services\";\n },\n },\n actors: {\n auth: authLogic,\n telemetry: telemetryLogic,\n systemPreferences: systemPreferencesLogic,\n remotes: remotesLogic,\n services: servicesLogic,\n },\n guards: {\n hasTag: (_, params: { hasTag: boolean }) => params.hasTag,\n },\n actions: {\n raiseAuthReady: raise({ type: \"boot.auth.ready\" }),\n raiseAuthFailed: raise({ type: \"boot.auth.failed\" }),\n raiseTelemetryReady: raise({\n type: \"boot.telemetry.ready\",\n }),\n startTelemetry: sendTo(\"telemetry\", {\n type: \"telemetry.start\",\n }),\n },\n}).createMachine({\n id: \"os\",\n context: ({ input }) => ({\n instance: createSanityInstance(),\n federationInstance: createInstance({\n name: \"workbench-applications\",\n plugins: [log(logger.debug)],\n }),\n userProperties: {\n version: input.version,\n organizationId: input.organizationId,\n environment: input.environment,\n userAgent: input.userAgent,\n },\n systemPreferencesAdapter: input.systemPreferencesAdapter,\n }),\n initial: \"booting\",\n invoke: [\n {\n id: \"auth\",\n systemId: \"auth\",\n src: \"auth\",\n input: ({ context }) => ({ instance: context.instance }),\n onSnapshot: [\n {\n guard: {\n type: \"hasTag\",\n params: ({ event }) => ({\n hasTag: event.snapshot.hasTag(\"authenticated\"),\n }),\n },\n actions: [{ type: \"raiseAuthReady\" }],\n },\n {\n guard: {\n type: \"hasTag\",\n params: ({ event }) => ({\n hasTag: event.snapshot.hasTag(\"error\"),\n }),\n },\n actions: [{ type: \"raiseAuthFailed\" }],\n },\n ],\n },\n {\n id: \"telemetry\",\n systemId: \"telemetry\",\n src: \"telemetry\",\n input: ({ context }) => ({\n instance: context.instance,\n ...context.userProperties,\n }),\n onSnapshot: [\n {\n guard: {\n type: \"hasTag\",\n params: ({ event }) => ({\n hasTag: event.snapshot.hasTag(\"telemetry-resolved\"),\n }),\n },\n actions: [{ type: \"raiseTelemetryReady\" }],\n },\n ],\n },\n {\n id: \"system-preferences\",\n systemId: \"system-preferences\",\n src: \"systemPreferences\",\n input: ({ context }) => ({ adapter: context.systemPreferencesAdapter }),\n },\n {\n id: \"remotes\",\n systemId: \"remotes\",\n src: \"remotes\",\n input: ({ context }) => ({ instance: context.federationInstance }),\n },\n {\n id: \"services\",\n systemId: \"services\",\n src: \"services\",\n input: ({ context }) => ({ instance: context.federationInstance }),\n },\n ],\n states: {\n booting: {\n initial: \"auth\",\n states: {\n auth: {\n on: {\n \"boot.auth.ready\": {\n target: \"telemetry\",\n actions: [{ type: \"startTelemetry\" }],\n },\n \"boot.auth.failed\": { target: \"error\" },\n },\n },\n telemetry: {\n on: {\n \"boot.telemetry.ready\": { target: \"done\" },\n },\n },\n error: {},\n done: { type: \"final\" },\n },\n onDone: { target: \"running\" },\n },\n running: {\n type: \"parallel\",\n },\n },\n});\n\n/**\n * Creates a set of default options for the OS machine. Forwards the workbench\n * user properties to the machine's input and wires the structured-logging\n * `inspect` callback. Browser-specific concerns (color-scheme seeding,\n * persistence) live in the {@link SystemPreferencesAdapter} the host passes\n * via `systemPreferencesAdapter`.\n * @public\n */\nexport function createOSOptions(input: OSInput) {\n return {\n id: \"os\",\n input,\n inspect,\n } satisfies ActorOptions<typeof os>;\n}\n"],"names":["log"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/workbench",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.22",
|
|
4
4
|
"description": "Workbench component for the Sanity Content Operating System",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/sanity-io/workbench/packages/@sanity/workbench#readme",
|
|
@@ -42,13 +42,12 @@
|
|
|
42
42
|
"./package.json": "./package.json"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
+
"@module-federation/runtime": "^2.4.0",
|
|
45
46
|
"@sanity/message-protocol": "^0.23.0",
|
|
46
47
|
"@sanity/telemetry": "^1.1.0",
|
|
47
48
|
"rxjs": "^7.8.2",
|
|
48
49
|
"semver": "^7.7.4",
|
|
49
|
-
"
|
|
50
|
-
"zod": "^4.3.6",
|
|
51
|
-
"@sanity/federation": "0.1.0-alpha.10"
|
|
50
|
+
"zod": "^4.3.6"
|
|
52
51
|
},
|
|
53
52
|
"devDependencies": {
|
|
54
53
|
"@sanity/pkg-utils": "^9.2.3",
|
|
@@ -56,11 +55,13 @@
|
|
|
56
55
|
"@types/semver": "^7.7.1",
|
|
57
56
|
"typescript": "^6.0.2",
|
|
58
57
|
"vite": "^7.3.1",
|
|
58
|
+
"xstate": "^5.32.0",
|
|
59
59
|
"@repo/oxc-config": "0.0.0",
|
|
60
60
|
"@repo/tsconfig": "0.0.1"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@sanity/sdk": "^2.9.0"
|
|
63
|
+
"@sanity/sdk": "^2.9.0",
|
|
64
|
+
"xstate": "^5.31.0"
|
|
64
65
|
},
|
|
65
66
|
"browserslist": "extends @sanity/browserslist-config",
|
|
66
67
|
"engines": {
|
package/src/_internal/render.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/// <reference types="vite/client" />
|
|
2
2
|
|
|
3
|
-
import { createInstance } from "@sanity/federation/runtime";
|
|
4
|
-
import { log } from "@sanity/federation/runtime/plugins/log";
|
|
5
3
|
import { BehaviorSubject, type Observable } from "rxjs";
|
|
6
4
|
|
|
7
5
|
import type { Config, RemoteModuleRenderOptions } from "../core/config";
|
|
8
6
|
import { logger } from "../core/log";
|
|
9
7
|
import type { LocalUserApplication } from "../core/user-applications/user-application";
|
|
8
|
+
import { createInstance, log } from "../system/module-federation";
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Options for rendering the workbench.
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { Resource as ProtocolResource } from "@sanity/message-protocol";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
type App,
|
|
5
|
+
type DockGroup,
|
|
3
6
|
type Interface,
|
|
4
7
|
InterfaceSchema,
|
|
5
8
|
type LocalApp,
|
|
@@ -10,16 +13,16 @@ import {
|
|
|
10
13
|
type Panel,
|
|
11
14
|
type PanelComponent,
|
|
12
15
|
type Service,
|
|
13
|
-
} from "
|
|
14
|
-
import type { Resource as ProtocolResource } from "@sanity/message-protocol";
|
|
16
|
+
} from "./interface";
|
|
15
17
|
|
|
16
|
-
// The interface model lives in
|
|
17
|
-
// `unstable_defineView` / `unstable_defineService`
|
|
18
|
-
//
|
|
19
|
-
// `
|
|
20
|
-
// app-typed subsets.
|
|
18
|
+
// The consumer/wire half of the interface model lives in `./interface`. The
|
|
19
|
+
// authoring half (`unstable_defineView` / `unstable_defineService`) lives with
|
|
20
|
+
// the CLI build helpers. Re-export the wire model so it stays part of the
|
|
21
|
+
// workbench app-model surface. `Panel`/`LocalPanel`, `Service`/`LocalService`,
|
|
22
|
+
// and `App`/`LocalApp` are the panel-, worker-, and app-typed subsets.
|
|
21
23
|
export {
|
|
22
24
|
type App,
|
|
25
|
+
type DockGroup,
|
|
23
26
|
type Interface,
|
|
24
27
|
InterfaceSchema,
|
|
25
28
|
type LocalApp,
|
|
@@ -60,7 +63,7 @@ export abstract class AbstractApplication<
|
|
|
60
63
|
|
|
61
64
|
/**
|
|
62
65
|
* The in-app route this application navigates to, or `null` when it isn't
|
|
63
|
-
* navigable as a full-page app (US5 — e.g. an SDK app with no `app` view).
|
|
66
|
+
* navigable as a full-page app (US5, spec 002-workbench-extension-api — e.g. an SDK app with no `app` view).
|
|
64
67
|
* The dock renders a navigable item only for a non-null `href`; the app
|
|
65
68
|
* routes 404 a `null`-href app on direct visit.
|
|
66
69
|
*/
|
|
@@ -96,7 +99,7 @@ export abstract class AbstractApplication<
|
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
/**
|
|
99
|
-
* Whether the application has a navigable full-page `app` view (US5). Defaults
|
|
102
|
+
* Whether the application has a navigable full-page `app` view (US5, spec 002-workbench-extension-api). Defaults
|
|
100
103
|
* to `true` — studios, Canvas, and Media Library are always navigable. An SDK
|
|
101
104
|
* app overrides this to derive it from whether it declares an `app` interface.
|
|
102
105
|
*/
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The consumer/wire half of the workbench extension interface model — the
|
|
5
|
+
* records the application service returns and the workbench renders from.
|
|
6
|
+
*
|
|
7
|
+
* The authoring half (`unstable_defineView` / `unstable_defineService` and the
|
|
8
|
+
* `*DeclarationSchema`s) lives with the CLI build helpers, not here: this module
|
|
9
|
+
* only models the wire shape the workbench consumes. Field names are snake_case
|
|
10
|
+
* to match the application service's JSON.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Fields every interface record carries. Per-type schemas add their
|
|
15
|
+
* `interface_type` discriminator on top.
|
|
16
|
+
*/
|
|
17
|
+
const interfaceBaseFields = {
|
|
18
|
+
id: z.string(),
|
|
19
|
+
deployment_id: z.string(),
|
|
20
|
+
name: z.string(),
|
|
21
|
+
entry_point: z.string(),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The `panel` interface record — a view that renders in the dock.
|
|
26
|
+
*/
|
|
27
|
+
const PanelInterfaceSchema = z.object({
|
|
28
|
+
...interfaceBaseFields,
|
|
29
|
+
interface_type: z.literal("panel"),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The `worker` interface record — a background service the workbench runs.
|
|
34
|
+
*/
|
|
35
|
+
const WorkerInterfaceSchema = z.object({
|
|
36
|
+
...interfaceBaseFields,
|
|
37
|
+
interface_type: z.literal("worker"),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The `app` interface record — an application's navigable full-page view. Its
|
|
42
|
+
* presence is the sole signal a branded app is navigable (US5, spec
|
|
43
|
+
* 002-workbench-extension-api).
|
|
44
|
+
*/
|
|
45
|
+
const AppInterfaceSchema = z.object({
|
|
46
|
+
...interfaceBaseFields,
|
|
47
|
+
interface_type: z.literal("app"),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* An interface record discriminated on `interface_type` — a `panel` renders in
|
|
52
|
+
* the dock, a `worker` runs a background service, an `app` is the navigable
|
|
53
|
+
* full-page view.
|
|
54
|
+
* @public
|
|
55
|
+
*/
|
|
56
|
+
export const InterfaceSchema = z.discriminatedUnion("interface_type", [
|
|
57
|
+
PanelInterfaceSchema,
|
|
58
|
+
WorkerInterfaceSchema,
|
|
59
|
+
AppInterfaceSchema,
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
/** @public */
|
|
63
|
+
export type Interface = z.output<typeof InterfaceSchema>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* An {@link Interface} without the service-assigned `id`/`deployment_id` a local
|
|
67
|
+
* dev server can't provide — the shape the workbench renders from.
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
70
|
+
export const LocalInterfaceSchema = z.discriminatedUnion("interface_type", [
|
|
71
|
+
PanelInterfaceSchema.omit({ id: true, deployment_id: true }),
|
|
72
|
+
WorkerInterfaceSchema.omit({ id: true, deployment_id: true }),
|
|
73
|
+
AppInterfaceSchema.omit({ id: true, deployment_id: true }),
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
/** @public */
|
|
77
|
+
export type LocalInterface = z.output<typeof LocalInterfaceSchema>;
|
|
78
|
+
|
|
79
|
+
/** The interface record for a given `interface_type`. @public */
|
|
80
|
+
export type InterfaceOfType<T extends Interface["interface_type"]> = Extract<
|
|
81
|
+
Interface,
|
|
82
|
+
{ interface_type: T }
|
|
83
|
+
>;
|
|
84
|
+
|
|
85
|
+
/** The {@link InterfaceOfType} counterpart without `id`/`deployment_id`. @public */
|
|
86
|
+
export type LocalInterfaceOfType<T extends LocalInterface["interface_type"]> =
|
|
87
|
+
Extract<LocalInterface, { interface_type: T }>;
|
|
88
|
+
|
|
89
|
+
/** @public */
|
|
90
|
+
export type Panel = InterfaceOfType<"panel">;
|
|
91
|
+
/** @public */
|
|
92
|
+
export type LocalPanel = LocalInterfaceOfType<"panel">;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* A service an application runs — the worker-typed interface record. `Service`/
|
|
96
|
+
* `LocalService` are the worker-typed subset of the interface model.
|
|
97
|
+
* @public
|
|
98
|
+
*/
|
|
99
|
+
export type Service = InterfaceOfType<"worker">;
|
|
100
|
+
/** @public */
|
|
101
|
+
export type LocalService = LocalInterfaceOfType<"worker">;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The navigable full-page view — its presence is the sole signal a branded app
|
|
105
|
+
* is navigable (US5, spec 002-workbench-extension-api).
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
108
|
+
export type App = InterfaceOfType<"app">;
|
|
109
|
+
/** @public */
|
|
110
|
+
export type LocalApp = LocalInterfaceOfType<"app">;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* A panel's view-component slots, in render order — each its own federation
|
|
114
|
+
* island (`${id}/views/${name}/${component}`). The authoring counterpart that
|
|
115
|
+
* drives the build's per-slot codegen lives with the CLI define helpers.
|
|
116
|
+
* @public
|
|
117
|
+
*/
|
|
118
|
+
export type PanelComponent = "title" | "panel";
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Where an application docks. The manifest's `group` value the workbench reads
|
|
122
|
+
* to place an app in the dock; the authoring counterpart that validates it on
|
|
123
|
+
* `unstable_defineApp` lives with the CLI define helpers.
|
|
124
|
+
* @public
|
|
125
|
+
*/
|
|
126
|
+
export type DockGroup = "dock.system" | "dock.applications" | "dock.user";
|
package/src/core/projects.ts
CHANGED
|
@@ -54,7 +54,7 @@ export const Project = z.object({
|
|
|
54
54
|
organizationId: OrganizationId,
|
|
55
55
|
metadata: z.object({
|
|
56
56
|
color: z.string().optional(),
|
|
57
|
-
externalStudioHost: z.string().optional(),
|
|
57
|
+
externalStudioHost: z.string().optional().nullable(),
|
|
58
58
|
initialTemplate: z.string().optional(),
|
|
59
59
|
cliInitializedAt: z.string().optional(),
|
|
60
60
|
integration: z.string().optional(),
|
|
@@ -97,7 +97,7 @@ export class CoreAppApplication extends UserApplication<
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
// Typed `string | null` so the UI-aware remote subclass can override it to
|
|
100
|
-
// `null` for a non-navigable app (US5); the core route itself is always set.
|
|
100
|
+
// `null` for a non-navigable app (US5, spec 002-workbench-extension-api); the core route itself is always set.
|
|
101
101
|
get href(): string | null {
|
|
102
102
|
return this.isLocal
|
|
103
103
|
? `/local/${this.id}`
|
|
@@ -100,7 +100,11 @@ export class StudioWorkspace extends AbstractApplication<
|
|
|
100
100
|
...this.workspace,
|
|
101
101
|
type: "studio",
|
|
102
102
|
userApplicationId: this.studio.id,
|
|
103
|
-
|
|
103
|
+
// The protocol still types `size`/`isAutoUpdating` as non-nullable,
|
|
104
|
+
// but the user-applications API reports both as nullable.
|
|
105
|
+
activeDeployment: this.studio.get(
|
|
106
|
+
"activeDeployment",
|
|
107
|
+
) as ProtocolStudioResource["activeDeployment"],
|
|
104
108
|
autoUpdatingVersion: this.studio.get("autoUpdatingVersion"),
|
|
105
109
|
dashboardStatus: this.studio.get("dashboardStatus"),
|
|
106
110
|
url: this.studio.url.toString(),
|
|
@@ -114,8 +114,8 @@ export const ActiveDeployment = z.object({
|
|
|
114
114
|
version: z.string(),
|
|
115
115
|
isActiveDeployment: z.boolean(),
|
|
116
116
|
userApplicationId: z.string(),
|
|
117
|
-
isAutoUpdating: z.boolean(),
|
|
118
|
-
size: z.number(),
|
|
117
|
+
isAutoUpdating: z.boolean().nullable(),
|
|
118
|
+
size: z.number().nullable(),
|
|
119
119
|
deployedAt: z.string(),
|
|
120
120
|
deployedBy: z.string(),
|
|
121
121
|
createdAt: z.string(),
|