@sanity/workbench 0.1.0-alpha.13 → 0.1.0-alpha.14
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.d.ts +231 -6
- package/dist/system.js +96 -4
- package/dist/system.js.map +1 -1
- package/package.json +3 -3
- package/src/system/index.ts +5 -0
- package/src/system/root.machine.ts +29 -4
- package/src/system/system-preferences.machine.ts +215 -0
package/dist/system.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ActorRefFromLogic } from "xstate";
|
|
2
2
|
import { AuthState } from "@sanity/sdk";
|
|
3
3
|
import { AuthStateType } from "@sanity/sdk";
|
|
4
|
+
import { CallbackActorLogic } from "xstate";
|
|
4
5
|
import { ConsentStatus } from "@sanity/telemetry";
|
|
5
6
|
import { CurrentUser } from "@sanity/sdk";
|
|
6
7
|
import { EventObject } from "xstate";
|
|
@@ -18,14 +19,21 @@ import { TelemetryStore } from "@sanity/telemetry";
|
|
|
18
19
|
*/
|
|
19
20
|
export declare interface AuthInput extends OSBaseInput {}
|
|
20
21
|
|
|
22
|
+
declare type ColorScheme = "light" | "dark";
|
|
23
|
+
|
|
24
|
+
declare type ColorSchemePreference = "system" | ColorScheme;
|
|
25
|
+
|
|
21
26
|
/**
|
|
22
|
-
* Creates a set of default options for the OS machine
|
|
23
|
-
* the
|
|
27
|
+
* Creates a set of default options for the OS machine. Forwards the workbench
|
|
28
|
+
* user properties to the machine's input and wires the structured-logging
|
|
29
|
+
* `inspect` callback. Browser-specific concerns (color-scheme seeding,
|
|
30
|
+
* persistence) live in the {@link SystemPreferencesAdapter} the host passes
|
|
31
|
+
* via `systemPreferencesAdapter`.
|
|
24
32
|
* @public
|
|
25
33
|
*/
|
|
26
34
|
export declare function createOSOptions(input: OSInput): {
|
|
27
35
|
id: string;
|
|
28
|
-
input:
|
|
36
|
+
input: OSInput;
|
|
29
37
|
inspect: (event: InspectionEvent) => void;
|
|
30
38
|
};
|
|
31
39
|
|
|
@@ -42,7 +50,12 @@ export declare interface LogoutInput extends OSBaseInput {}
|
|
|
42
50
|
* import { os, createOSOptions } from "@sanity/workbench/system";
|
|
43
51
|
* import { useActor } from "@xstate/react";
|
|
44
52
|
*
|
|
45
|
-
* const [state, send] = useActor(os, createOSOptions(
|
|
53
|
+
* const [state, send] = useActor(os, createOSOptions({
|
|
54
|
+
* version: "1.0.0",
|
|
55
|
+
* organizationId: "...",
|
|
56
|
+
* environment: "production",
|
|
57
|
+
* userAgent: navigator.userAgent,
|
|
58
|
+
* }));
|
|
46
59
|
* ```
|
|
47
60
|
*/
|
|
48
61
|
export declare const os: StateMachine<
|
|
@@ -216,6 +229,77 @@ export declare const os: StateMachine<
|
|
|
216
229
|
>
|
|
217
230
|
>
|
|
218
231
|
| undefined;
|
|
232
|
+
"system-preferences"?:
|
|
233
|
+
| ActorRefFromLogic<
|
|
234
|
+
StateMachine<
|
|
235
|
+
SystemPreferencesContext & {
|
|
236
|
+
adapter: SystemPreferencesAdapter | undefined;
|
|
237
|
+
},
|
|
238
|
+
| {
|
|
239
|
+
type: "preferredColorScheme.set";
|
|
240
|
+
preferredColorScheme: ("light" | "dark") | "system";
|
|
241
|
+
}
|
|
242
|
+
| {
|
|
243
|
+
type: "osColorScheme.set";
|
|
244
|
+
osColorScheme: "light" | "dark";
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
[x: string]:
|
|
248
|
+
| ActorRefFromLogic<
|
|
249
|
+
CallbackActorLogic<
|
|
250
|
+
{
|
|
251
|
+
type: "preferredColorScheme.set";
|
|
252
|
+
preferredColorScheme: ("light" | "dark") | "system";
|
|
253
|
+
},
|
|
254
|
+
SystemPreferencesAdapter | undefined,
|
|
255
|
+
SystemPreferencesEvent
|
|
256
|
+
>
|
|
257
|
+
>
|
|
258
|
+
| undefined;
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
src: "adapterBridge";
|
|
262
|
+
logic: CallbackActorLogic<
|
|
263
|
+
{
|
|
264
|
+
type: "preferredColorScheme.set";
|
|
265
|
+
preferredColorScheme: ("light" | "dark") | "system";
|
|
266
|
+
},
|
|
267
|
+
SystemPreferencesAdapter | undefined,
|
|
268
|
+
SystemPreferencesEvent
|
|
269
|
+
>;
|
|
270
|
+
id: string | undefined;
|
|
271
|
+
},
|
|
272
|
+
| {
|
|
273
|
+
type: "setPreferredColorScheme";
|
|
274
|
+
params: {
|
|
275
|
+
preferredColorScheme: ("light" | "dark") | "system";
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
| {
|
|
279
|
+
type: "setOsColorScheme";
|
|
280
|
+
params: {
|
|
281
|
+
osColorScheme: "light" | "dark";
|
|
282
|
+
};
|
|
283
|
+
},
|
|
284
|
+
never,
|
|
285
|
+
never,
|
|
286
|
+
"ready",
|
|
287
|
+
string,
|
|
288
|
+
{
|
|
289
|
+
adapter?: SystemPreferencesAdapter;
|
|
290
|
+
},
|
|
291
|
+
NonReducibleUnknown,
|
|
292
|
+
EventObject,
|
|
293
|
+
MetaObject,
|
|
294
|
+
{
|
|
295
|
+
id: "system-preferences";
|
|
296
|
+
states: {
|
|
297
|
+
readonly ready: {};
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
>
|
|
301
|
+
>
|
|
302
|
+
| undefined;
|
|
219
303
|
},
|
|
220
304
|
| {
|
|
221
305
|
src: "telemetry";
|
|
@@ -375,6 +459,77 @@ export declare const os: StateMachine<
|
|
|
375
459
|
}
|
|
376
460
|
>;
|
|
377
461
|
id: "auth";
|
|
462
|
+
}
|
|
463
|
+
| {
|
|
464
|
+
src: "systemPreferences";
|
|
465
|
+
logic: StateMachine<
|
|
466
|
+
SystemPreferencesContext & {
|
|
467
|
+
adapter: SystemPreferencesAdapter | undefined;
|
|
468
|
+
},
|
|
469
|
+
| {
|
|
470
|
+
type: "preferredColorScheme.set";
|
|
471
|
+
preferredColorScheme: ("light" | "dark") | "system";
|
|
472
|
+
}
|
|
473
|
+
| {
|
|
474
|
+
type: "osColorScheme.set";
|
|
475
|
+
osColorScheme: "light" | "dark";
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
[x: string]:
|
|
479
|
+
| ActorRefFromLogic<
|
|
480
|
+
CallbackActorLogic<
|
|
481
|
+
{
|
|
482
|
+
type: "preferredColorScheme.set";
|
|
483
|
+
preferredColorScheme: ("light" | "dark") | "system";
|
|
484
|
+
},
|
|
485
|
+
SystemPreferencesAdapter | undefined,
|
|
486
|
+
SystemPreferencesEvent
|
|
487
|
+
>
|
|
488
|
+
>
|
|
489
|
+
| undefined;
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
src: "adapterBridge";
|
|
493
|
+
logic: CallbackActorLogic<
|
|
494
|
+
{
|
|
495
|
+
type: "preferredColorScheme.set";
|
|
496
|
+
preferredColorScheme: ("light" | "dark") | "system";
|
|
497
|
+
},
|
|
498
|
+
SystemPreferencesAdapter | undefined,
|
|
499
|
+
SystemPreferencesEvent
|
|
500
|
+
>;
|
|
501
|
+
id: string | undefined;
|
|
502
|
+
},
|
|
503
|
+
| {
|
|
504
|
+
type: "setPreferredColorScheme";
|
|
505
|
+
params: {
|
|
506
|
+
preferredColorScheme: ("light" | "dark") | "system";
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
| {
|
|
510
|
+
type: "setOsColorScheme";
|
|
511
|
+
params: {
|
|
512
|
+
osColorScheme: "light" | "dark";
|
|
513
|
+
};
|
|
514
|
+
},
|
|
515
|
+
never,
|
|
516
|
+
never,
|
|
517
|
+
"ready",
|
|
518
|
+
string,
|
|
519
|
+
{
|
|
520
|
+
adapter?: SystemPreferencesAdapter;
|
|
521
|
+
},
|
|
522
|
+
NonReducibleUnknown,
|
|
523
|
+
EventObject,
|
|
524
|
+
MetaObject,
|
|
525
|
+
{
|
|
526
|
+
id: "system-preferences";
|
|
527
|
+
states: {
|
|
528
|
+
readonly ready: {};
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
>;
|
|
532
|
+
id: "system-preferences";
|
|
378
533
|
},
|
|
379
534
|
| {
|
|
380
535
|
type: "raiseAuthReady";
|
|
@@ -404,7 +559,7 @@ export declare const os: StateMachine<
|
|
|
404
559
|
booting: "error" | "done" | "telemetry" | "auth";
|
|
405
560
|
},
|
|
406
561
|
string,
|
|
407
|
-
|
|
562
|
+
OSInput,
|
|
408
563
|
NonReducibleUnknown,
|
|
409
564
|
EventObject,
|
|
410
565
|
MetaObject,
|
|
@@ -433,9 +588,79 @@ declare interface OSBaseInput extends Pick<OSContext, "instance"> {}
|
|
|
433
588
|
declare type OSContext = {
|
|
434
589
|
instance: SanityInstance;
|
|
435
590
|
userProperties: WorkbenchUserProperties;
|
|
591
|
+
systemPreferencesAdapter: SystemPreferencesAdapter | undefined;
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
declare type OSInput = WorkbenchUserProperties & {
|
|
595
|
+
systemPreferencesAdapter?: SystemPreferencesAdapter;
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Adapter interface the host implements to give the system-preferences
|
|
600
|
+
* machine access to the user's environment (OS color scheme, persistent
|
|
601
|
+
* storage, cross-context change notifications).
|
|
602
|
+
*
|
|
603
|
+
* The package owns all orchestration — synchronous seeding, idempotent
|
|
604
|
+
* persistence, mapping cleared storage to `"system"`. The host's
|
|
605
|
+
* implementation is pure DOM/storage glue: read, write, subscribe.
|
|
606
|
+
* @public
|
|
607
|
+
*/
|
|
608
|
+
export declare type SystemPreferencesAdapter = {
|
|
609
|
+
/** Read the user's stored preference. `null` means "no preference set"
|
|
610
|
+
* (the machine treats this as `"system"`). */
|
|
611
|
+
getPreferredColorScheme: () => ColorSchemePreference | null;
|
|
612
|
+
/** Write the user's preference to persistent storage. */
|
|
613
|
+
persistPreferredColorScheme: (value: ColorSchemePreference) => void;
|
|
614
|
+
/** Subscribe to cross-context preference changes (e.g. another tab
|
|
615
|
+
* writing to the shared storage). The callback receives the new stored
|
|
616
|
+
* value (or `null` if it was cleared). Returns an unsubscribe function. */
|
|
617
|
+
subscribePreferredColorScheme: (
|
|
618
|
+
callback: (next: ColorSchemePreference | null) => void,
|
|
619
|
+
) => () => void;
|
|
620
|
+
/** Read the current OS-detected color scheme. */
|
|
621
|
+
getOsColorScheme: () => ColorScheme;
|
|
622
|
+
/** Subscribe to OS color-scheme changes (e.g. user flipping dark mode).
|
|
623
|
+
* Returns an unsubscribe function. */
|
|
624
|
+
subscribeOsColorScheme: (callback: (next: ColorScheme) => void) => () => void;
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* The system-preferences machine's context. Consumers read fields directly
|
|
629
|
+
* (e.g. via `useSelector`) rather than going through a resolver utility —
|
|
630
|
+
* the action handlers keep `colorScheme` in sync with `preferredColorScheme`
|
|
631
|
+
* and `osColorScheme`.
|
|
632
|
+
*
|
|
633
|
+
* Note: `colorScheme` is intentionally stored as derived state in context so
|
|
634
|
+
* consumers can read the resolved value directly without a utility. The
|
|
635
|
+
* action handlers below are the single source of truth for the resolution.
|
|
636
|
+
* @public
|
|
637
|
+
*/
|
|
638
|
+
export declare type SystemPreferencesContext = {
|
|
639
|
+
/** User's color scheme choice; `system` defers to the OS preference. */
|
|
640
|
+
preferredColorScheme: ColorSchemePreference;
|
|
641
|
+
/** Last reported OS color scheme. Used to resolve `colorScheme` when the
|
|
642
|
+
* preference is `system`. */
|
|
643
|
+
osColorScheme: ColorScheme;
|
|
644
|
+
/** Resolved color scheme — what the UI should render. Recomputed by the
|
|
645
|
+
* action handlers whenever an input changes. */
|
|
646
|
+
colorScheme: ColorScheme;
|
|
436
647
|
};
|
|
437
648
|
|
|
438
|
-
|
|
649
|
+
/**
|
|
650
|
+
* Events the system-preferences machine accepts. Both originate from the
|
|
651
|
+
* host's adapter — `preferredColorScheme.set` is also forwarded back to it
|
|
652
|
+
* so it can persist the user's choice.
|
|
653
|
+
* @public
|
|
654
|
+
*/
|
|
655
|
+
export declare type SystemPreferencesEvent =
|
|
656
|
+
| {
|
|
657
|
+
type: "preferredColorScheme.set";
|
|
658
|
+
preferredColorScheme: ColorSchemePreference;
|
|
659
|
+
}
|
|
660
|
+
| {
|
|
661
|
+
type: "osColorScheme.set";
|
|
662
|
+
osColorScheme: ColorScheme;
|
|
663
|
+
};
|
|
439
664
|
|
|
440
665
|
/**
|
|
441
666
|
* @internal
|
package/dist/system.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getAuthState, logout, AuthStateType, getClient, createSanityInstance } from "@sanity/sdk";
|
|
2
|
-
import { fromObservable, fromPromise, setup, assign, sendTo, raise } from "xstate";
|
|
2
|
+
import { fromObservable, fromPromise, setup, assign, fromCallback, sendTo, raise } from "xstate";
|
|
3
3
|
import "./_chunks-es/studio.js";
|
|
4
4
|
import { logger } from "./_chunks-es/index.js";
|
|
5
5
|
import { createSessionId, createBatchedStore } from "@sanity/telemetry";
|
|
@@ -198,7 +198,91 @@ const authStateLogic = fromObservable(
|
|
|
198
198
|
log.debug("action", event.action);
|
|
199
199
|
break;
|
|
200
200
|
}
|
|
201
|
-
},
|
|
201
|
+
}, DEFAULT_PREFERRED_COLOR_SCHEME = "system", DEFAULT_OS_COLOR_SCHEME = "light", resolveColorScheme = (preferred, osColorScheme) => preferred === "system" ? osColorScheme : preferred, adapterBridgeLogic = fromCallback(({ input: adapter, sendBack, receive }) => {
|
|
202
|
+
if (!adapter) return;
|
|
203
|
+
const unsubscribePreferredColorScheme = adapter.subscribePreferredColorScheme(
|
|
204
|
+
(next) => {
|
|
205
|
+
sendBack({
|
|
206
|
+
type: "preferredColorScheme.set",
|
|
207
|
+
preferredColorScheme: next ?? "system"
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
), unsubscribeOs = adapter.subscribeOsColorScheme((next) => {
|
|
211
|
+
sendBack({ type: "osColorScheme.set", osColorScheme: next });
|
|
212
|
+
});
|
|
213
|
+
return receive((event) => {
|
|
214
|
+
adapter.getPreferredColorScheme() !== event.preferredColorScheme && adapter.persistPreferredColorScheme(event.preferredColorScheme);
|
|
215
|
+
}), () => {
|
|
216
|
+
unsubscribePreferredColorScheme(), unsubscribeOs();
|
|
217
|
+
};
|
|
218
|
+
}), systemPreferencesLogic = setup({
|
|
219
|
+
types: {
|
|
220
|
+
input: {},
|
|
221
|
+
context: {},
|
|
222
|
+
events: {}
|
|
223
|
+
},
|
|
224
|
+
actors: {
|
|
225
|
+
adapterBridge: adapterBridgeLogic
|
|
226
|
+
},
|
|
227
|
+
actions: {
|
|
228
|
+
setPreferredColorScheme: assign({
|
|
229
|
+
preferredColorScheme: (_, params) => params.preferredColorScheme,
|
|
230
|
+
colorScheme: ({ context }, params) => resolveColorScheme(params.preferredColorScheme, context.osColorScheme)
|
|
231
|
+
}),
|
|
232
|
+
setOsColorScheme: assign({
|
|
233
|
+
osColorScheme: (_, params) => params.osColorScheme,
|
|
234
|
+
colorScheme: ({ context }, params) => resolveColorScheme(context.preferredColorScheme, params.osColorScheme)
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
}).createMachine({
|
|
238
|
+
id: "system-preferences",
|
|
239
|
+
initial: "ready",
|
|
240
|
+
context: ({ input }) => {
|
|
241
|
+
const adapter = input.adapter, preferredColorScheme = adapter?.getPreferredColorScheme() ?? DEFAULT_PREFERRED_COLOR_SCHEME, osColorScheme = adapter?.getOsColorScheme() ?? DEFAULT_OS_COLOR_SCHEME;
|
|
242
|
+
return {
|
|
243
|
+
adapter,
|
|
244
|
+
preferredColorScheme,
|
|
245
|
+
osColorScheme,
|
|
246
|
+
colorScheme: resolveColorScheme(preferredColorScheme, osColorScheme)
|
|
247
|
+
};
|
|
248
|
+
},
|
|
249
|
+
invoke: {
|
|
250
|
+
id: "adapter",
|
|
251
|
+
src: "adapterBridge",
|
|
252
|
+
input: ({ context }) => context.adapter
|
|
253
|
+
},
|
|
254
|
+
states: {
|
|
255
|
+
ready: {
|
|
256
|
+
on: {
|
|
257
|
+
"preferredColorScheme.set": {
|
|
258
|
+
actions: [
|
|
259
|
+
{
|
|
260
|
+
type: "setPreferredColorScheme",
|
|
261
|
+
params: ({ event }) => ({
|
|
262
|
+
preferredColorScheme: event.preferredColorScheme
|
|
263
|
+
})
|
|
264
|
+
},
|
|
265
|
+
// Forward to the adapter bridge so it can persist the user's
|
|
266
|
+
// choice. The bridge guards against redundant writes, so
|
|
267
|
+
// round-tripping a `preferredColorScheme.set` it sourced itself
|
|
268
|
+
// (e.g. from a `storage` event in another tab) is a no-op.
|
|
269
|
+
sendTo("adapter", ({ event }) => event)
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
"osColorScheme.set": {
|
|
273
|
+
actions: [
|
|
274
|
+
{
|
|
275
|
+
type: "setOsColorScheme",
|
|
276
|
+
params: ({ event }) => ({
|
|
277
|
+
osColorScheme: event.osColorScheme
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}), TELEMETRY_API_VERSION = "2024-11-12", FLUSH_INTERVAL_MS = 3e4, checkConsentLogic = fromPromise(async ({ input, signal }) => {
|
|
202
286
|
try {
|
|
203
287
|
return await getClient(input.instance, {
|
|
204
288
|
apiVersion: TELEMETRY_API_VERSION
|
|
@@ -319,7 +403,8 @@ const authStateLogic = fromObservable(
|
|
|
319
403
|
},
|
|
320
404
|
actors: {
|
|
321
405
|
auth: authLogic,
|
|
322
|
-
telemetry: telemetryLogic
|
|
406
|
+
telemetry: telemetryLogic,
|
|
407
|
+
systemPreferences: systemPreferencesLogic
|
|
323
408
|
},
|
|
324
409
|
guards: {
|
|
325
410
|
hasTag: (_, params) => params.hasTag
|
|
@@ -343,7 +428,8 @@ const authStateLogic = fromObservable(
|
|
|
343
428
|
organizationId: input.organizationId,
|
|
344
429
|
environment: input.environment,
|
|
345
430
|
userAgent: input.userAgent
|
|
346
|
-
}
|
|
431
|
+
},
|
|
432
|
+
systemPreferencesAdapter: input.systemPreferencesAdapter
|
|
347
433
|
}),
|
|
348
434
|
initial: "booting",
|
|
349
435
|
invoke: [
|
|
@@ -392,6 +478,12 @@ const authStateLogic = fromObservable(
|
|
|
392
478
|
actions: [{ type: "raiseTelemetryReady" }]
|
|
393
479
|
}
|
|
394
480
|
]
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
id: "system-preferences",
|
|
484
|
+
systemId: "system-preferences",
|
|
485
|
+
src: "systemPreferences",
|
|
486
|
+
input: ({ context }) => ({ adapter: context.systemPreferencesAdapter })
|
|
395
487
|
}
|
|
396
488
|
],
|
|
397
489
|
states: {
|
package/dist/system.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","sources":["../src/system/auth.machine.ts","../src/system/inspect.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 { 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 telemetryLogic,\n type WorkbenchUserProperties,\n} from \"./telemetry.machine\";\n\ntype OSInput = WorkbenchUserProperties;\ntype OSContext = {\n instance: SanityInstance;\n userProperties: WorkbenchUserProperties;\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 * ```\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 },\n },\n actors: {\n auth: authLogic,\n telemetry: telemetryLogic,\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 }),\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 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, including passing\n * the sanity configuration for the internal instance.\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/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":";;;;;AAkBA,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,UACZ,MAAM,OAAO,MAAM,UAAU,GAAG,CAAC;AAEvC,UAAQ,MAAM,MAAA;AAAA,IACZ,KAAK,oBAAoB;AACvB,UAAI,MAAM,YAAY,MAAM,QAAQ;AACpC;AAAA,IACF;AAAA,IACA,KAAK;AACH,UAAI,MAAM,SAAS,MAAM,KAAK;AAC9B;AAAA,IACF,KAAK;AACH,UAAI,MAAM,UAAU,MAAM,MAAM;AAChC;AAAA,EAAA;AAEN,GCXM,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,GCpIY,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,EAMb,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,mBAAmB;AAAA,EAAA;AAAA,EAErB,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,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,EACvE;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;"}
|
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.14",
|
|
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",
|
|
@@ -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/
|
|
60
|
-
"@repo/
|
|
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"
|
package/src/system/index.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export type { AuthInput, LogoutInput } from "./auth.machine";
|
|
2
|
+
export type {
|
|
3
|
+
SystemPreferencesAdapter,
|
|
4
|
+
SystemPreferencesContext,
|
|
5
|
+
SystemPreferencesEvent,
|
|
6
|
+
} from "./system-preferences.machine";
|
|
2
7
|
export { os, createOSOptions } from "./root.machine";
|
|
3
8
|
export type {
|
|
4
9
|
TelemetryInput,
|
|
@@ -3,15 +3,23 @@ import { raise, sendTo, setup, type ActorOptions } from "xstate";
|
|
|
3
3
|
|
|
4
4
|
import { authLogic } from "./auth.machine";
|
|
5
5
|
import { inspect } from "./inspect";
|
|
6
|
+
import {
|
|
7
|
+
type SystemPreferencesAdapter,
|
|
8
|
+
systemPreferencesLogic,
|
|
9
|
+
} from "./system-preferences.machine";
|
|
6
10
|
import {
|
|
7
11
|
telemetryLogic,
|
|
8
12
|
type WorkbenchUserProperties,
|
|
9
13
|
} from "./telemetry.machine";
|
|
10
14
|
|
|
11
|
-
type OSInput = WorkbenchUserProperties
|
|
15
|
+
type OSInput = WorkbenchUserProperties & {
|
|
16
|
+
systemPreferencesAdapter?: SystemPreferencesAdapter;
|
|
17
|
+
};
|
|
18
|
+
|
|
12
19
|
type OSContext = {
|
|
13
20
|
instance: SanityInstance;
|
|
14
21
|
userProperties: WorkbenchUserProperties;
|
|
22
|
+
systemPreferencesAdapter: SystemPreferencesAdapter | undefined;
|
|
15
23
|
};
|
|
16
24
|
|
|
17
25
|
/**
|
|
@@ -28,7 +36,12 @@ export interface OSBaseInput extends Pick<OSContext, "instance"> {}
|
|
|
28
36
|
* import { os, createOSOptions } from "@sanity/workbench/system";
|
|
29
37
|
* import { useActor } from "@xstate/react";
|
|
30
38
|
*
|
|
31
|
-
* const [state, send] = useActor(os, createOSOptions(
|
|
39
|
+
* const [state, send] = useActor(os, createOSOptions({
|
|
40
|
+
* version: "1.0.0",
|
|
41
|
+
* organizationId: "...",
|
|
42
|
+
* environment: "production",
|
|
43
|
+
* userAgent: navigator.userAgent,
|
|
44
|
+
* }));
|
|
32
45
|
* ```
|
|
33
46
|
*/
|
|
34
47
|
export const os = setup({
|
|
@@ -43,11 +56,13 @@ export const os = setup({
|
|
|
43
56
|
children: {} as {
|
|
44
57
|
auth: "auth";
|
|
45
58
|
telemetry: "telemetry";
|
|
59
|
+
"system-preferences": "systemPreferences";
|
|
46
60
|
},
|
|
47
61
|
},
|
|
48
62
|
actors: {
|
|
49
63
|
auth: authLogic,
|
|
50
64
|
telemetry: telemetryLogic,
|
|
65
|
+
systemPreferences: systemPreferencesLogic,
|
|
51
66
|
},
|
|
52
67
|
guards: {
|
|
53
68
|
hasTag: (_, params: { hasTag: boolean }) => params.hasTag,
|
|
@@ -72,6 +87,7 @@ export const os = setup({
|
|
|
72
87
|
environment: input.environment,
|
|
73
88
|
userAgent: input.userAgent,
|
|
74
89
|
},
|
|
90
|
+
systemPreferencesAdapter: input.systemPreferencesAdapter,
|
|
75
91
|
}),
|
|
76
92
|
initial: "booting",
|
|
77
93
|
invoke: [
|
|
@@ -121,6 +137,12 @@ export const os = setup({
|
|
|
121
137
|
},
|
|
122
138
|
],
|
|
123
139
|
},
|
|
140
|
+
{
|
|
141
|
+
id: "system-preferences",
|
|
142
|
+
systemId: "system-preferences",
|
|
143
|
+
src: "systemPreferences",
|
|
144
|
+
input: ({ context }) => ({ adapter: context.systemPreferencesAdapter }),
|
|
145
|
+
},
|
|
124
146
|
],
|
|
125
147
|
states: {
|
|
126
148
|
booting: {
|
|
@@ -152,8 +174,11 @@ export const os = setup({
|
|
|
152
174
|
});
|
|
153
175
|
|
|
154
176
|
/**
|
|
155
|
-
* Creates a set of default options for the OS machine
|
|
156
|
-
* the
|
|
177
|
+
* Creates a set of default options for the OS machine. Forwards the workbench
|
|
178
|
+
* user properties to the machine's input and wires the structured-logging
|
|
179
|
+
* `inspect` callback. Browser-specific concerns (color-scheme seeding,
|
|
180
|
+
* persistence) live in the {@link SystemPreferencesAdapter} the host passes
|
|
181
|
+
* via `systemPreferencesAdapter`.
|
|
157
182
|
* @public
|
|
158
183
|
*/
|
|
159
184
|
export function createOSOptions(input: OSInput) {
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { assign, fromCallback, sendTo, setup } from "xstate";
|
|
2
|
+
|
|
3
|
+
type ColorScheme = "light" | "dark";
|
|
4
|
+
|
|
5
|
+
type ColorSchemePreference = "system" | ColorScheme;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The system-preferences machine's context. Consumers read fields directly
|
|
9
|
+
* (e.g. via `useSelector`) rather than going through a resolver utility —
|
|
10
|
+
* the action handlers keep `colorScheme` in sync with `preferredColorScheme`
|
|
11
|
+
* and `osColorScheme`.
|
|
12
|
+
*
|
|
13
|
+
* Note: `colorScheme` is intentionally stored as derived state in context so
|
|
14
|
+
* consumers can read the resolved value directly without a utility. The
|
|
15
|
+
* action handlers below are the single source of truth for the resolution.
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export type SystemPreferencesContext = {
|
|
19
|
+
/** User's color scheme choice; `system` defers to the OS preference. */
|
|
20
|
+
preferredColorScheme: ColorSchemePreference;
|
|
21
|
+
/** Last reported OS color scheme. Used to resolve `colorScheme` when the
|
|
22
|
+
* preference is `system`. */
|
|
23
|
+
osColorScheme: ColorScheme;
|
|
24
|
+
/** Resolved color scheme — what the UI should render. Recomputed by the
|
|
25
|
+
* action handlers whenever an input changes. */
|
|
26
|
+
colorScheme: ColorScheme;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const DEFAULT_PREFERRED_COLOR_SCHEME: ColorSchemePreference = "system";
|
|
30
|
+
const DEFAULT_OS_COLOR_SCHEME: ColorScheme = "light";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Events the system-preferences machine accepts. Both originate from the
|
|
34
|
+
* host's adapter — `preferredColorScheme.set` is also forwarded back to it
|
|
35
|
+
* so it can persist the user's choice.
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
export type SystemPreferencesEvent =
|
|
39
|
+
| {
|
|
40
|
+
type: "preferredColorScheme.set";
|
|
41
|
+
preferredColorScheme: ColorSchemePreference;
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
type: "osColorScheme.set";
|
|
45
|
+
osColorScheme: ColorScheme;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Adapter interface the host implements to give the system-preferences
|
|
50
|
+
* machine access to the user's environment (OS color scheme, persistent
|
|
51
|
+
* storage, cross-context change notifications).
|
|
52
|
+
*
|
|
53
|
+
* The package owns all orchestration — synchronous seeding, idempotent
|
|
54
|
+
* persistence, mapping cleared storage to `"system"`. The host's
|
|
55
|
+
* implementation is pure DOM/storage glue: read, write, subscribe.
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
export type SystemPreferencesAdapter = {
|
|
59
|
+
/** Read the user's stored preference. `null` means "no preference set"
|
|
60
|
+
* (the machine treats this as `"system"`). */
|
|
61
|
+
getPreferredColorScheme: () => ColorSchemePreference | null;
|
|
62
|
+
/** Write the user's preference to persistent storage. */
|
|
63
|
+
persistPreferredColorScheme: (value: ColorSchemePreference) => void;
|
|
64
|
+
/** Subscribe to cross-context preference changes (e.g. another tab
|
|
65
|
+
* writing to the shared storage). The callback receives the new stored
|
|
66
|
+
* value (or `null` if it was cleared). Returns an unsubscribe function. */
|
|
67
|
+
subscribePreferredColorScheme: (
|
|
68
|
+
callback: (next: ColorSchemePreference | null) => void,
|
|
69
|
+
) => () => void;
|
|
70
|
+
/** Read the current OS-detected color scheme. */
|
|
71
|
+
getOsColorScheme: () => ColorScheme;
|
|
72
|
+
/** Subscribe to OS color-scheme changes (e.g. user flipping dark mode).
|
|
73
|
+
* Returns an unsubscribe function. */
|
|
74
|
+
subscribeOsColorScheme: (callback: (next: ColorScheme) => void) => () => void;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const resolveColorScheme = (
|
|
78
|
+
preferred: ColorSchemePreference,
|
|
79
|
+
osColorScheme: ColorScheme,
|
|
80
|
+
): ColorScheme => (preferred === "system" ? osColorScheme : preferred);
|
|
81
|
+
|
|
82
|
+
// Internal bridge actor — subscribes to the host's adapter for runtime
|
|
83
|
+
// changes and persists user-driven preference changes when the parent
|
|
84
|
+
// forwards them. No-op if the host didn't pass an adapter (SSR, tests).
|
|
85
|
+
type AdapterBridgeReceiveEvent = Extract<
|
|
86
|
+
SystemPreferencesEvent,
|
|
87
|
+
{ type: "preferredColorScheme.set" }
|
|
88
|
+
>;
|
|
89
|
+
|
|
90
|
+
const adapterBridgeLogic = fromCallback<
|
|
91
|
+
AdapterBridgeReceiveEvent,
|
|
92
|
+
SystemPreferencesAdapter | undefined,
|
|
93
|
+
SystemPreferencesEvent
|
|
94
|
+
>(({ input: adapter, sendBack, receive }) => {
|
|
95
|
+
if (!adapter) return;
|
|
96
|
+
|
|
97
|
+
const unsubscribePreferredColorScheme = adapter.subscribePreferredColorScheme(
|
|
98
|
+
(next) => {
|
|
99
|
+
// Falls back to `"system"` so an external clear (another tab deleting
|
|
100
|
+
// the key) resets the preference rather than silently keeping the
|
|
101
|
+
// previous value.
|
|
102
|
+
sendBack({
|
|
103
|
+
type: "preferredColorScheme.set",
|
|
104
|
+
preferredColorScheme: next ?? "system",
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const unsubscribeOs = adapter.subscribeOsColorScheme((next) => {
|
|
110
|
+
sendBack({ type: "osColorScheme.set", osColorScheme: next });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
receive((event) => {
|
|
114
|
+
// Idempotent: skip writes that match the current stored value so a
|
|
115
|
+
// `preferredColorScheme.set` originating from cross-context change
|
|
116
|
+
// doesn't loop back into another write.
|
|
117
|
+
if (adapter.getPreferredColorScheme() === event.preferredColorScheme)
|
|
118
|
+
return;
|
|
119
|
+
|
|
120
|
+
adapter.persistPreferredColorScheme(event.preferredColorScheme);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return () => {
|
|
124
|
+
unsubscribePreferredColorScheme();
|
|
125
|
+
unsubscribeOs();
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @internal
|
|
131
|
+
*/
|
|
132
|
+
export const systemPreferencesLogic = setup({
|
|
133
|
+
types: {
|
|
134
|
+
input: {} as { adapter?: SystemPreferencesAdapter },
|
|
135
|
+
context: {} as SystemPreferencesContext & {
|
|
136
|
+
adapter: SystemPreferencesAdapter | undefined;
|
|
137
|
+
},
|
|
138
|
+
events: {} as SystemPreferencesEvent,
|
|
139
|
+
},
|
|
140
|
+
actors: {
|
|
141
|
+
adapterBridge: adapterBridgeLogic,
|
|
142
|
+
},
|
|
143
|
+
actions: {
|
|
144
|
+
setPreferredColorScheme: assign({
|
|
145
|
+
preferredColorScheme: (
|
|
146
|
+
_,
|
|
147
|
+
params: { preferredColorScheme: ColorSchemePreference },
|
|
148
|
+
) => params.preferredColorScheme,
|
|
149
|
+
colorScheme: (
|
|
150
|
+
{ context },
|
|
151
|
+
params: { preferredColorScheme: ColorSchemePreference },
|
|
152
|
+
) =>
|
|
153
|
+
resolveColorScheme(params.preferredColorScheme, context.osColorScheme),
|
|
154
|
+
}),
|
|
155
|
+
setOsColorScheme: assign({
|
|
156
|
+
osColorScheme: (_, params: { osColorScheme: ColorScheme }) =>
|
|
157
|
+
params.osColorScheme,
|
|
158
|
+
colorScheme: ({ context }, params: { osColorScheme: ColorScheme }) =>
|
|
159
|
+
resolveColorScheme(context.preferredColorScheme, params.osColorScheme),
|
|
160
|
+
}),
|
|
161
|
+
},
|
|
162
|
+
}).createMachine({
|
|
163
|
+
id: "system-preferences",
|
|
164
|
+
initial: "ready",
|
|
165
|
+
context: ({ input }) => {
|
|
166
|
+
const adapter = input.adapter;
|
|
167
|
+
const preferredColorScheme =
|
|
168
|
+
adapter?.getPreferredColorScheme() ?? DEFAULT_PREFERRED_COLOR_SCHEME;
|
|
169
|
+
const osColorScheme =
|
|
170
|
+
adapter?.getOsColorScheme() ?? DEFAULT_OS_COLOR_SCHEME;
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
adapter,
|
|
174
|
+
preferredColorScheme,
|
|
175
|
+
osColorScheme,
|
|
176
|
+
colorScheme: resolveColorScheme(preferredColorScheme, osColorScheme),
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
invoke: {
|
|
180
|
+
id: "adapter",
|
|
181
|
+
src: "adapterBridge",
|
|
182
|
+
input: ({ context }) => context.adapter,
|
|
183
|
+
},
|
|
184
|
+
states: {
|
|
185
|
+
ready: {
|
|
186
|
+
on: {
|
|
187
|
+
"preferredColorScheme.set": {
|
|
188
|
+
actions: [
|
|
189
|
+
{
|
|
190
|
+
type: "setPreferredColorScheme",
|
|
191
|
+
params: ({ event }) => ({
|
|
192
|
+
preferredColorScheme: event.preferredColorScheme,
|
|
193
|
+
}),
|
|
194
|
+
},
|
|
195
|
+
// Forward to the adapter bridge so it can persist the user's
|
|
196
|
+
// choice. The bridge guards against redundant writes, so
|
|
197
|
+
// round-tripping a `preferredColorScheme.set` it sourced itself
|
|
198
|
+
// (e.g. from a `storage` event in another tab) is a no-op.
|
|
199
|
+
sendTo("adapter", ({ event }) => event),
|
|
200
|
+
],
|
|
201
|
+
},
|
|
202
|
+
"osColorScheme.set": {
|
|
203
|
+
actions: [
|
|
204
|
+
{
|
|
205
|
+
type: "setOsColorScheme",
|
|
206
|
+
params: ({ event }) => ({
|
|
207
|
+
osColorScheme: event.osColorScheme,
|
|
208
|
+
}),
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
});
|