@sanity/workbench 0.1.0-alpha.16 → 0.1.0-alpha.18

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/system.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { getAuthState, logout, AuthStateType, getClient, createSanityInstance } from "@sanity/sdk";
2
- import { fromObservable, fromPromise, setup, assign, fromCallback, sendTo, raise } from "xstate";
2
+ import { fromObservable, fromPromise, setup, assign, sendParent, fromCallback, sendTo, raise } from "xstate";
3
3
  import "./_chunks-es/studio.js";
4
4
  import { logger } from "./_chunks-es/index.js";
5
+ import { createInstance } from "@sanity/federation/runtime";
6
+ import { log } from "@sanity/federation/runtime/plugins/log";
5
7
  import { createSessionId, createBatchedStore } from "@sanity/telemetry";
6
8
  const authStateLogic = fromObservable(
7
9
  ({ input }) => getAuthState(input.instance).observable
@@ -185,20 +187,168 @@ const authStateLogic = fromObservable(
185
187
  segments.unshift(current.id ?? current.sessionId), current = current._parent;
186
188
  return segments.join(":");
187
189
  }, inspect = (event) => {
188
- const ref = event.actorRef, log = logger.child(actorPath(ref));
190
+ const ref = event.actorRef, log2 = logger.child(actorPath(ref));
189
191
  switch (event.type) {
190
192
  case "@xstate.snapshot": {
191
- log.debug("snapshot", event.snapshot);
193
+ log2.debug("snapshot", event.snapshot);
192
194
  break;
193
195
  }
194
196
  case "@xstate.event":
195
- log.debug("event", event.event);
197
+ log2.debug("event", event.event);
196
198
  break;
197
199
  case "@xstate.action":
198
- log.debug("action", event.action);
200
+ log2.debug("action", event.action);
199
201
  break;
200
202
  }
201
- }, DEFAULT_PREFERRED_COLOR_SCHEME = "system", DEFAULT_OS_COLOR_SCHEME = "light", resolveColorScheme = (preferred, osColorScheme) => preferred === "system" ? osColorScheme : preferred, adapterBridgeLogic = fromCallback(({ input: adapter, sendBack, receive }) => {
203
+ };
204
+ class ModuleShapeError extends Error {
205
+ constructor(remoteId) {
206
+ super(`Remote "${remoteId}" did not expose a render function`);
207
+ }
208
+ }
209
+ const REMOTE_MODULE = "App", loadLogic = fromPromise(
210
+ async ({ input }) => {
211
+ input.instance.registerRemotes([{ name: input.id, entry: input.entry }]);
212
+ const remoteModule = await input.instance.loadRemote(
213
+ `${input.id}/${REMOTE_MODULE}`
214
+ );
215
+ if (!remoteModule || typeof remoteModule.render != "function")
216
+ throw new ModuleShapeError(input.id);
217
+ return remoteModule;
218
+ }
219
+ ), remoteLogic = setup({
220
+ types: {
221
+ input: {},
222
+ context: {},
223
+ tags: {}
224
+ },
225
+ actors: {
226
+ load: loadLogic
227
+ },
228
+ actions: {
229
+ setModule: assign({
230
+ module: (_, params) => params.module,
231
+ error: () => null
232
+ }),
233
+ setError: assign({
234
+ module: () => null,
235
+ error: (_, params) => normaliseError(params.error)
236
+ })
237
+ }
238
+ }).createMachine({
239
+ id: "remote",
240
+ initial: "loading",
241
+ context: ({ input }) => ({
242
+ ...input,
243
+ module: null,
244
+ error: null
245
+ }),
246
+ states: {
247
+ loading: {
248
+ tags: ["loading"],
249
+ invoke: {
250
+ src: "load",
251
+ input: ({ context }) => ({
252
+ id: context.id,
253
+ entry: context.entry,
254
+ instance: context.instance
255
+ }),
256
+ onDone: {
257
+ target: "loaded",
258
+ actions: [
259
+ {
260
+ type: "setModule",
261
+ params: ({ event }) => ({ module: event.output })
262
+ }
263
+ ]
264
+ },
265
+ onError: {
266
+ target: "error",
267
+ actions: [
268
+ {
269
+ type: "setError",
270
+ params: ({ event }) => ({ error: event.error })
271
+ }
272
+ ]
273
+ }
274
+ }
275
+ },
276
+ loaded: {
277
+ tags: ["ready"],
278
+ entry: sendParent(({ context }) => ({
279
+ type: "remote.settled",
280
+ id: context.id,
281
+ status: "loaded"
282
+ }))
283
+ },
284
+ error: {
285
+ tags: ["failed"],
286
+ entry: sendParent(({ context }) => ({
287
+ type: "remote.settled",
288
+ id: context.id,
289
+ status: "error"
290
+ }))
291
+ }
292
+ }
293
+ });
294
+ function normaliseError(error) {
295
+ return error instanceof Error ? { message: error.message, cause: error } : { message: String(error), cause: error };
296
+ }
297
+ const remotesLogic = setup({
298
+ types: {
299
+ context: {},
300
+ events: {}
301
+ },
302
+ actors: {
303
+ remote: remoteLogic
304
+ },
305
+ guards: {
306
+ remoteNotKnown: ({ context }, params) => !context.children.has(params.id)
307
+ },
308
+ actions: {
309
+ spawnRemote: assign({
310
+ children: ({ context, spawn }, params) => {
311
+ const ref = spawn("remote", {
312
+ id: params.id,
313
+ systemId: `remotes.${params.id}`,
314
+ input: {
315
+ id: params.id,
316
+ entry: params.entry,
317
+ instance: context.instance
318
+ }
319
+ });
320
+ return new Map(context.children).set(params.id, ref);
321
+ }
322
+ })
323
+ }
324
+ }).createMachine({
325
+ id: "remotes",
326
+ context: () => ({
327
+ instance: createInstance({
328
+ name: "workbench-applications",
329
+ plugins: [log(logger.debug)]
330
+ }),
331
+ children: /* @__PURE__ */ new Map()
332
+ }),
333
+ on: {
334
+ "remote.load.request": {
335
+ guard: {
336
+ type: "remoteNotKnown",
337
+ params: ({ event }) => ({ id: event.id })
338
+ },
339
+ actions: [
340
+ {
341
+ type: "spawnRemote",
342
+ params: ({ event }) => ({ id: event.id, entry: event.entry })
343
+ }
344
+ ]
345
+ },
346
+ // Reserved for future supervision/retry. Forwarded by per-remote
347
+ // children on entry to `loaded` or `error`; currently a no-op so the
348
+ // event is part of the typed surface rather than a silent unknown.
349
+ "remote.settled": {}
350
+ }
351
+ }), DEFAULT_PREFERRED_COLOR_SCHEME = "system", DEFAULT_OS_COLOR_SCHEME = "light", resolveColorScheme = (preferred, osColorScheme) => preferred === "system" ? osColorScheme : preferred, adapterBridgeLogic = fromCallback(({ input: adapter, sendBack, receive }) => {
202
352
  if (!adapter) return;
203
353
  const unsubscribePreferredColorScheme = adapter.subscribePreferredColorScheme(
204
354
  (next) => {
@@ -404,7 +554,8 @@ const authStateLogic = fromObservable(
404
554
  actors: {
405
555
  auth: authLogic,
406
556
  telemetry: telemetryLogic,
407
- systemPreferences: systemPreferencesLogic
557
+ systemPreferences: systemPreferencesLogic,
558
+ remotes: remotesLogic
408
559
  },
409
560
  guards: {
410
561
  hasTag: (_, params) => params.hasTag
@@ -484,6 +635,11 @@ const authStateLogic = fromObservable(
484
635
  systemId: "system-preferences",
485
636
  src: "systemPreferences",
486
637
  input: ({ context }) => ({ adapter: context.systemPreferencesAdapter })
638
+ },
639
+ {
640
+ id: "remotes",
641
+ systemId: "remotes",
642
+ src: "remotes"
487
643
  }
488
644
  ],
489
645
  states: {
@@ -1 +1 @@
1
- {"version":3,"file":"system.js","sources":["../src/system/auth.machine.ts","../src/system/inspect.ts","../src/system/system-preferences.machine.ts","../src/system/telemetry.machine.ts","../src/system/root.machine.ts"],"sourcesContent":["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 { 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 { authLogic } from \"./auth.machine\";\nimport { inspect } from \"./inspect\";\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 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 },\n },\n actors: {\n auth: authLogic,\n telemetry: telemetryLogic,\n systemPreferences: systemPreferencesLogic,\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 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 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":[],"mappings":"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"}
1
+ {"version":3,"file":"system.js","sources":["../src/system/auth.machine.ts","../src/system/inspect.ts","../src/system/remote.machine.ts","../src/system/remotes.machine.ts","../src/system/system-preferences.machine.ts","../src/system/telemetry.machine.ts","../src/system/root.machine.ts"],"sourcesContent":["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 { assign, fromPromise, sendParent, setup } from \"xstate\";\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 * @public\n */\nexport interface LoadedRemoteModule {\n render: (\n rootElement: HTMLElement,\n options?: RemoteRenderOptions,\n ) => () => void;\n}\n\n/**\n * @public\n */\nexport interface RemoteError {\n message: string;\n cause: unknown;\n}\n\n/**\n * Thrown by the load actor when a remote responds successfully but does\n * not expose a `render` function. Surfaced via `RemoteError.cause` for\n * consumers that need to discriminate.\n * @internal\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 * @internal\n */\nexport interface RemoteInput {\n id: string;\n entry: string;\n instance: FederationInstance;\n}\n\ntype RemoteContext = RemoteInput & {\n module: LoadedRemoteModule | null;\n error: RemoteError | null;\n};\n\nconst REMOTE_MODULE = \"App\";\n\nconst loadLogic = fromPromise<LoadedRemoteModule, RemoteInput>(\n async ({ input }) => {\n input.instance.registerRemotes([{ name: input.id, entry: input.entry }]);\n const remoteModule = await input.instance.loadRemote<unknown>(\n `${input.id}/${REMOTE_MODULE}`,\n );\n if (\n !remoteModule ||\n typeof (remoteModule as { render?: unknown }).render !== \"function\"\n ) {\n throw new ModuleShapeError(input.id);\n }\n return remoteModule as LoadedRemoteModule;\n },\n);\n\n/**\n * Lifecycle machine for a single federated application remote.\n *\n * Spawned by the {@link remotesLogic} supervisor on demand. Each instance\n * owns one remote's load lifecycle: `loading` → `loaded | error`. Tags\n * (`loading` / `ready` / `failed`) drive the UI contract — state names\n * 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: LoadedRemoteModule }) => 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 id: context.id,\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 id: context.id,\n status: \"loaded\" as const,\n })),\n },\n error: {\n tags: [\"failed\"],\n entry: sendParent(({ context }) => ({\n type: \"remote.settled\" as const,\n id: context.id,\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 createInstance,\n type FederationInstance,\n} from \"@sanity/federation/runtime\";\nimport { log } from \"@sanity/federation/runtime/plugins/log\";\nimport { type ActorRefFrom, assign, setup } from \"xstate\";\n\nimport { logger } from \"../core/log\";\nimport { remoteLogic } from \"./remote.machine\";\n\ntype RemotesContext = {\n instance: FederationInstance;\n children: Map<string, ActorRefFrom<typeof remoteLogic>>;\n};\n\ntype RemotesEvent =\n | { type: \"remote.load.request\"; id: string; entry: string }\n | { type: \"remote.settled\"; id: string; status: \"loaded\" | \"error\" };\n\n/**\n * Supervisor machine for federated application remotes.\n *\n * Owns a single {@link FederationInstance} (the `workbench-applications`\n * instance) and spawns one {@link remoteLogic} child per requested\n * remote. The supervisor is invoked at the root of the OS machine for\n * inspector visibility (`[sanity-workbench:os:remotes]`) — boot does\n * not gate on it.\n *\n * @internal\n */\nexport const remotesLogic = setup({\n types: {\n context: {} as RemotesContext,\n events: {} as RemotesEvent,\n },\n actors: {\n remote: remoteLogic,\n },\n guards: {\n remoteNotKnown: ({ context }, params: { id: string }) =>\n !context.children.has(params.id),\n },\n actions: {\n spawnRemote: assign({\n children: ({ context, spawn }, params: { id: string; entry: string }) => {\n const ref = spawn(\"remote\", {\n id: params.id,\n systemId: `remotes.${params.id}`,\n input: {\n id: params.id,\n entry: params.entry,\n instance: context.instance,\n },\n });\n return new Map(context.children).set(params.id, ref);\n },\n }),\n },\n}).createMachine({\n id: \"remotes\",\n context: () => ({\n instance: createInstance({\n name: \"workbench-applications\",\n plugins: [log(logger.debug)],\n }),\n children: new Map(),\n }),\n on: {\n \"remote.load.request\": {\n guard: {\n type: \"remoteNotKnown\",\n params: ({ event }) => ({ id: event.id }),\n },\n actions: [\n {\n type: \"spawnRemote\",\n params: ({ event }) => ({ id: event.id, entry: event.entry }),\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, 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 { authLogic } from \"./auth.machine\";\nimport { inspect } from \"./inspect\";\nimport { remotesLogic } from \"./remotes.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 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 },\n },\n actors: {\n auth: authLogic,\n telemetry: telemetryLogic,\n systemPreferences: systemPreferencesLogic,\n remotes: remotesLogic,\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 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 },\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.16",
3
+ "version": "0.1.0-alpha.18",
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",
@@ -48,7 +48,7 @@
48
48
  "semver": "^7.7.4",
49
49
  "xstate": "^5.31.0",
50
50
  "zod": "^4.3.6",
51
- "@sanity/federation": "0.1.0-alpha.7"
51
+ "@sanity/federation": "0.1.0-alpha.8"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@sanity/pkg-utils": "^9.2.3",
@@ -56,8 +56,8 @@
56
56
  "@types/semver": "^7.7.1",
57
57
  "typescript": "^6.0.2",
58
58
  "vite": "^7.3.1",
59
- "@repo/tsconfig": "0.0.1",
60
- "@repo/oxc-config": "0.0.0"
59
+ "@repo/oxc-config": "0.0.0",
60
+ "@repo/tsconfig": "0.0.1"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "@sanity/sdk": "^2.9.0"
@@ -164,7 +164,7 @@ export class StudioApplication extends UserApplication<
164
164
  workspace.basePath === DEFAULT_WORKSPACE_DATA.basePath &&
165
165
  workspace.title === DEFAULT_WORKSPACE_DATA.title;
166
166
 
167
- return new StudioWorkspace(this, workspace, p, isDefaultWorkspace);
167
+ return this.createWorkspace(workspace, p, isDefaultWorkspace);
168
168
  }),
169
169
  );
170
170
 
@@ -179,6 +179,20 @@ export class StudioApplication extends UserApplication<
179
179
  this.projects = Array.from(usedProjects);
180
180
  }
181
181
 
182
+ /**
183
+ * Factory hook called for each workspace during construction. Subclasses
184
+ * override this to substitute a `StudioWorkspace` subclass (e.g. a UI-aware
185
+ * variant in a downstream package) without re-implementing the constructor's
186
+ * workspace-derivation logic.
187
+ */
188
+ protected createWorkspace(
189
+ workspace: Workspace,
190
+ project: Project<false, false>,
191
+ isDefaultWorkspace: boolean,
192
+ ): StudioWorkspace {
193
+ return new StudioWorkspace(this, workspace, project, isDefaultWorkspace);
194
+ }
195
+
182
196
  get href() {
183
197
  return this.isLocal
184
198
  ? `/local/${this.id}`
@@ -1,4 +1,10 @@
1
1
  export type { AuthInput, LogoutInput } from "./auth.machine";
2
+ export type {
3
+ LoadedRemoteModule,
4
+ RemoteError,
5
+ RemoteInput,
6
+ RemoteRenderOptions,
7
+ } from "./remote.machine";
2
8
  export type {
3
9
  SystemPreferencesAdapter,
4
10
  SystemPreferencesContext,
@@ -0,0 +1,173 @@
1
+ import type { FederationInstance } from "@sanity/federation/runtime";
2
+ import { assign, fromPromise, sendParent, setup } from "xstate";
3
+
4
+ /**
5
+ * @public
6
+ */
7
+ export interface RemoteRenderOptions {
8
+ basePath?: string;
9
+ scheme?: "light" | "dark";
10
+ /**
11
+ * This is a temporary measure designed to authenticate federated
12
+ * studios & SDK apps before we write a working protocol.
13
+ */
14
+ unstable_temporaryToken?: string | null;
15
+ }
16
+
17
+ /**
18
+ * @public
19
+ */
20
+ export interface LoadedRemoteModule {
21
+ render: (
22
+ rootElement: HTMLElement,
23
+ options?: RemoteRenderOptions,
24
+ ) => () => void;
25
+ }
26
+
27
+ /**
28
+ * @public
29
+ */
30
+ export interface RemoteError {
31
+ message: string;
32
+ cause: unknown;
33
+ }
34
+
35
+ /**
36
+ * Thrown by the load actor when a remote responds successfully but does
37
+ * not expose a `render` function. Surfaced via `RemoteError.cause` for
38
+ * consumers that need to discriminate.
39
+ * @internal
40
+ */
41
+ export class ModuleShapeError extends Error {
42
+ constructor(remoteId: string) {
43
+ super(`Remote "${remoteId}" did not expose a render function`);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * @internal
49
+ */
50
+ export interface RemoteInput {
51
+ id: string;
52
+ entry: string;
53
+ instance: FederationInstance;
54
+ }
55
+
56
+ type RemoteContext = RemoteInput & {
57
+ module: LoadedRemoteModule | null;
58
+ error: RemoteError | null;
59
+ };
60
+
61
+ const REMOTE_MODULE = "App";
62
+
63
+ const loadLogic = fromPromise<LoadedRemoteModule, RemoteInput>(
64
+ async ({ input }) => {
65
+ input.instance.registerRemotes([{ name: input.id, entry: input.entry }]);
66
+ const remoteModule = await input.instance.loadRemote<unknown>(
67
+ `${input.id}/${REMOTE_MODULE}`,
68
+ );
69
+ if (
70
+ !remoteModule ||
71
+ typeof (remoteModule as { render?: unknown }).render !== "function"
72
+ ) {
73
+ throw new ModuleShapeError(input.id);
74
+ }
75
+ return remoteModule as LoadedRemoteModule;
76
+ },
77
+ );
78
+
79
+ /**
80
+ * Lifecycle machine for a single federated application remote.
81
+ *
82
+ * Spawned by the {@link remotesLogic} supervisor on demand. Each instance
83
+ * owns one remote's load lifecycle: `loading` → `loaded | error`. Tags
84
+ * (`loading` / `ready` / `failed`) drive the UI contract — state names
85
+ * are internal.
86
+ *
87
+ * The machine sends a `remote.settled` event to its parent on entry to
88
+ * either terminal state, reserved for future supervision/retry.
89
+ *
90
+ * @internal
91
+ */
92
+ export const remoteLogic = setup({
93
+ types: {
94
+ input: {} as RemoteInput,
95
+ context: {} as RemoteContext,
96
+ tags: {} as "loading" | "ready" | "failed",
97
+ },
98
+ actors: {
99
+ load: loadLogic,
100
+ },
101
+ actions: {
102
+ setModule: assign({
103
+ module: (_, params: { module: LoadedRemoteModule }) => params.module,
104
+ error: () => null,
105
+ }),
106
+ setError: assign({
107
+ module: () => null,
108
+ error: (_, params: { error: unknown }) => normaliseError(params.error),
109
+ }),
110
+ },
111
+ }).createMachine({
112
+ id: "remote",
113
+ initial: "loading",
114
+ context: ({ input }) => ({
115
+ ...input,
116
+ module: null,
117
+ error: null,
118
+ }),
119
+ states: {
120
+ loading: {
121
+ tags: ["loading"],
122
+ invoke: {
123
+ src: "load",
124
+ input: ({ context }) => ({
125
+ id: context.id,
126
+ entry: context.entry,
127
+ instance: context.instance,
128
+ }),
129
+ onDone: {
130
+ target: "loaded",
131
+ actions: [
132
+ {
133
+ type: "setModule",
134
+ params: ({ event }) => ({ module: event.output }),
135
+ },
136
+ ],
137
+ },
138
+ onError: {
139
+ target: "error",
140
+ actions: [
141
+ {
142
+ type: "setError",
143
+ params: ({ event }) => ({ error: event.error }),
144
+ },
145
+ ],
146
+ },
147
+ },
148
+ },
149
+ loaded: {
150
+ tags: ["ready"],
151
+ entry: sendParent(({ context }) => ({
152
+ type: "remote.settled" as const,
153
+ id: context.id,
154
+ status: "loaded" as const,
155
+ })),
156
+ },
157
+ error: {
158
+ tags: ["failed"],
159
+ entry: sendParent(({ context }) => ({
160
+ type: "remote.settled" as const,
161
+ id: context.id,
162
+ status: "error" as const,
163
+ })),
164
+ },
165
+ },
166
+ });
167
+
168
+ function normaliseError(error: unknown): RemoteError {
169
+ if (error instanceof Error) {
170
+ return { message: error.message, cause: error };
171
+ }
172
+ return { message: String(error), cause: error };
173
+ }