@sanity/workbench 0.1.0-alpha.2 → 0.1.0-alpha.21
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/README.md +24 -0
- package/dist/_chunks-es/index.js +39 -0
- package/dist/_chunks-es/index.js.map +1 -0
- package/dist/_chunks-es/module-federation.js +59 -0
- package/dist/_chunks-es/module-federation.js.map +1 -0
- package/dist/_chunks-es/studio.js +892 -0
- package/dist/_chunks-es/studio.js.map +1 -0
- package/dist/_internal.d.ts +16 -4
- package/dist/_internal.js +34 -27
- package/dist/_internal.js.map +1 -1
- package/dist/core.d.ts +2250 -0
- package/dist/core.js +74 -0
- package/dist/core.js.map +1 -0
- package/dist/system.d.ts +2135 -0
- package/dist/system.js +887 -0
- package/dist/system.js.map +1 -0
- package/package.json +34 -6
- package/src/_exports/core.ts +1 -0
- package/src/_exports/system.ts +1 -0
- package/src/_internal/index.ts +2 -1
- package/src/_internal/render.ts +72 -43
- package/src/core/applications/application-list.ts +104 -0
- package/src/core/applications/application.ts +177 -0
- package/src/core/applications/interface.ts +126 -0
- package/src/core/canvases.ts +92 -0
- package/src/core/config.ts +34 -0
- package/src/core/env.ts +43 -0
- package/src/core/index.ts +13 -0
- package/src/core/log/index.ts +125 -0
- package/src/core/media-libraries.ts +93 -0
- package/src/core/organizations.ts +115 -0
- package/src/core/projects.ts +114 -0
- package/src/core/shared/urls.ts +129 -0
- package/src/core/user-applications/core-app.ts +148 -0
- package/src/core/user-applications/studios/index.ts +3 -0
- package/src/core/user-applications/studios/schemas.ts +128 -0
- package/src/core/user-applications/studios/studio.ts +533 -0
- package/src/core/user-applications/studios/workspace.ts +156 -0
- package/src/core/user-applications/user-application.ts +222 -0
- package/src/system/auth.machine.ts +223 -0
- package/src/system/index.ts +22 -0
- package/src/system/inspect.ts +40 -0
- package/src/system/load-federated-module.ts +53 -0
- package/src/system/module-federation.ts +116 -0
- package/src/system/remote.machine.ts +219 -0
- package/src/system/remotes.machine.ts +92 -0
- package/src/system/root.machine.ts +224 -0
- package/src/system/service.machine.ts +207 -0
- package/src/system/services.machine.ts +120 -0
- package/src/system/system-preferences.machine.ts +215 -0
- package/src/system/telemetry.machine.ts +179 -0
- package/src/_internal/render.test.ts +0 -18
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { assign, fromPromise, sendParent, setup } from "xstate";
|
|
2
|
+
|
|
3
|
+
import { loadRemoteModule } from "./load-federated-module";
|
|
4
|
+
import type { FederationInstance } from "./module-federation";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export interface RemoteRenderOptions {
|
|
10
|
+
basePath?: string;
|
|
11
|
+
scheme?: "light" | "dark";
|
|
12
|
+
/**
|
|
13
|
+
* This is a temporary measure designed to authenticate federated
|
|
14
|
+
* studios & SDK apps before we write a working protocol.
|
|
15
|
+
*/
|
|
16
|
+
unstable_temporaryToken?: string | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A loaded render-contract module. `TProps` is what its `render` accepts —
|
|
21
|
+
* `RemoteRenderOptions` for an application's full-page view, the view's props
|
|
22
|
+
* for a dock-panel component.
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export interface LoadedRemoteModule<TProps = RemoteRenderOptions> {
|
|
26
|
+
render: (rootElement: HTMLElement, props?: TProps) => () => void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A worker service's loader module — the `worker` interface's expose. Carries
|
|
31
|
+
* the worker bundle URL (root-relative to the app origin) for the host to
|
|
32
|
+
* bootstrap, not a render function; the services counterpart of
|
|
33
|
+
* {@link LoadedRemoteModule}.
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
export interface ServiceLoaderModule {
|
|
37
|
+
url: string;
|
|
38
|
+
type: string;
|
|
39
|
+
name: string;
|
|
40
|
+
version: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The federated-module shape each interface type exposes, keyed by
|
|
45
|
+
* `interface_type`. Every interface — `panel`, `app`, `worker` — loads through
|
|
46
|
+
* the same {@link remoteLogic} lifecycle; this maps what its loaded module looks
|
|
47
|
+
* like so each consumer narrows the machine's shape-agnostic `module` to the
|
|
48
|
+
* right type: a render contract for `panel`/`app` (rendered by an island), a
|
|
49
|
+
* worker loader for `worker` (run as a Web Worker, never rendered).
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
export interface RemoteModuleByInterfaceType {
|
|
53
|
+
panel: LoadedRemoteModule;
|
|
54
|
+
app: LoadedRemoteModule;
|
|
55
|
+
worker: ServiceLoaderModule;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
export interface RemoteError {
|
|
62
|
+
message: string;
|
|
63
|
+
cause: unknown;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Thrown by a render consumer (e.g. the island) when a loaded module doesn't
|
|
68
|
+
* expose a `render` function. Render-specific — `remoteLogic` itself is
|
|
69
|
+
* shape-agnostic, so this lives with the consumer that needs the contract, not
|
|
70
|
+
* the loader. Surfaced via `RemoteError.cause` for consumers that discriminate.
|
|
71
|
+
* @public
|
|
72
|
+
*/
|
|
73
|
+
export class ModuleShapeError extends Error {
|
|
74
|
+
constructor(remoteId: string) {
|
|
75
|
+
super(`Remote "${remoteId}" did not expose a render function`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Thrown by the load actor when a remote's expose resolves empty — the module
|
|
81
|
+
* isn't published, or `loadRemote` returned nothing. Generic across interface
|
|
82
|
+
* types; the shape-specific check (a render function, a worker URL) is the
|
|
83
|
+
* consumer's, since `remoteLogic` loads every interface the same way.
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
export class ModuleLoadError extends Error {
|
|
87
|
+
constructor(remoteId: string) {
|
|
88
|
+
super(`Remote module "${remoteId}" failed to load`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @internal
|
|
94
|
+
*/
|
|
95
|
+
export interface RemoteInput {
|
|
96
|
+
/** Fully-qualified module id — `${appId}/${expose}`. One child per moduleId. */
|
|
97
|
+
moduleId: string;
|
|
98
|
+
entry: string;
|
|
99
|
+
instance: FederationInstance;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
type RemoteContext = RemoteInput & {
|
|
103
|
+
/** The loaded module, shape-agnostic — each consumer narrows it. @see {@link RemoteModuleByInterfaceType} */
|
|
104
|
+
module: unknown;
|
|
105
|
+
error: RemoteError | null;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const loadLogic = fromPromise<unknown, RemoteInput>(async ({ input }) => {
|
|
109
|
+
const remoteModule = await loadRemoteModule<unknown>(input.instance, {
|
|
110
|
+
moduleId: input.moduleId,
|
|
111
|
+
entry: input.entry,
|
|
112
|
+
});
|
|
113
|
+
// The loader is interface-agnostic: it only guarantees a module came back.
|
|
114
|
+
// Render-vs-worker shape validation is the consumer's (a panel/app island
|
|
115
|
+
// checks `render`; a service checks `url`).
|
|
116
|
+
if (remoteModule == null) {
|
|
117
|
+
throw new ModuleLoadError(input.moduleId);
|
|
118
|
+
}
|
|
119
|
+
return remoteModule;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Lifecycle machine for a single federated interface module — an application's
|
|
124
|
+
* `App` entry, one view component, or a worker service's loader. Interface-
|
|
125
|
+
* agnostic: it loads and tracks any module, leaving the shape contract
|
|
126
|
+
* (render vs. worker URL) to the consumer.
|
|
127
|
+
*
|
|
128
|
+
* Spawned by the {@link remotesLogic} supervisor on demand, one per remote id
|
|
129
|
+
* (`${appId}/${moduleId}`). Each instance owns one module's load lifecycle:
|
|
130
|
+
* `loading` → `loaded | error`. Tags (`loading` / `ready` / `failed`) drive the
|
|
131
|
+
* UI contract — state names are internal.
|
|
132
|
+
*
|
|
133
|
+
* The machine sends a `remote.settled` event to its parent on entry to
|
|
134
|
+
* either terminal state, reserved for future supervision/retry.
|
|
135
|
+
*
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
export const remoteLogic = setup({
|
|
139
|
+
types: {
|
|
140
|
+
input: {} as RemoteInput,
|
|
141
|
+
context: {} as RemoteContext,
|
|
142
|
+
tags: {} as "loading" | "ready" | "failed",
|
|
143
|
+
},
|
|
144
|
+
actors: {
|
|
145
|
+
load: loadLogic,
|
|
146
|
+
},
|
|
147
|
+
actions: {
|
|
148
|
+
setModule: assign({
|
|
149
|
+
module: (_, params: { module: unknown }) => params.module,
|
|
150
|
+
error: () => null,
|
|
151
|
+
}),
|
|
152
|
+
setError: assign({
|
|
153
|
+
module: () => null,
|
|
154
|
+
error: (_, params: { error: unknown }) => normaliseError(params.error),
|
|
155
|
+
}),
|
|
156
|
+
},
|
|
157
|
+
}).createMachine({
|
|
158
|
+
id: "remote",
|
|
159
|
+
initial: "loading",
|
|
160
|
+
context: ({ input }) => ({
|
|
161
|
+
...input,
|
|
162
|
+
module: null,
|
|
163
|
+
error: null,
|
|
164
|
+
}),
|
|
165
|
+
states: {
|
|
166
|
+
loading: {
|
|
167
|
+
tags: ["loading"],
|
|
168
|
+
invoke: {
|
|
169
|
+
src: "load",
|
|
170
|
+
input: ({ context }) => ({
|
|
171
|
+
moduleId: context.moduleId,
|
|
172
|
+
entry: context.entry,
|
|
173
|
+
instance: context.instance,
|
|
174
|
+
}),
|
|
175
|
+
onDone: {
|
|
176
|
+
target: "loaded",
|
|
177
|
+
actions: [
|
|
178
|
+
{
|
|
179
|
+
type: "setModule",
|
|
180
|
+
params: ({ event }) => ({ module: event.output }),
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
onError: {
|
|
185
|
+
target: "error",
|
|
186
|
+
actions: [
|
|
187
|
+
{
|
|
188
|
+
type: "setError",
|
|
189
|
+
params: ({ event }) => ({ error: event.error }),
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
loaded: {
|
|
196
|
+
tags: ["ready"],
|
|
197
|
+
entry: sendParent(({ context }) => ({
|
|
198
|
+
type: "remote.settled" as const,
|
|
199
|
+
moduleId: context.moduleId,
|
|
200
|
+
status: "loaded" as const,
|
|
201
|
+
})),
|
|
202
|
+
},
|
|
203
|
+
error: {
|
|
204
|
+
tags: ["failed"],
|
|
205
|
+
entry: sendParent(({ context }) => ({
|
|
206
|
+
type: "remote.settled" as const,
|
|
207
|
+
moduleId: context.moduleId,
|
|
208
|
+
status: "error" as const,
|
|
209
|
+
})),
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
function normaliseError(error: unknown): RemoteError {
|
|
215
|
+
if (error instanceof Error) {
|
|
216
|
+
return { message: error.message, cause: error };
|
|
217
|
+
}
|
|
218
|
+
return { message: String(error), cause: error };
|
|
219
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { type ActorRefFrom, assign, setup } from "xstate";
|
|
2
|
+
|
|
3
|
+
import { type FederationInstance } from "./module-federation";
|
|
4
|
+
import { remoteLogic } from "./remote.machine";
|
|
5
|
+
|
|
6
|
+
/** The shared federation instance, supplied by the root machine. */
|
|
7
|
+
type RemotesInput = {
|
|
8
|
+
instance: FederationInstance;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type RemotesContext = {
|
|
12
|
+
instance: FederationInstance;
|
|
13
|
+
children: Map<string, ActorRefFrom<typeof remoteLogic>>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type RemotesEvent =
|
|
17
|
+
| { type: "remote.load.request"; moduleId: string; entry: string }
|
|
18
|
+
| { type: "remote.settled"; moduleId: string; status: "loaded" | "error" };
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Supervisor machine for federated modules.
|
|
22
|
+
*
|
|
23
|
+
* Uses the shared {@link FederationInstance} (the `workbench-applications`
|
|
24
|
+
* instance, supplied by the root machine and shared with `services`) and spawns
|
|
25
|
+
* one {@link remoteLogic} child per remote id (`${appId}/${moduleId}`) — so an
|
|
26
|
+
* application's `App` entry and each of its dock-panel view components load (and
|
|
27
|
+
* are tracked) independently. The
|
|
28
|
+
* supervisor is invoked at the root of the OS machine for inspector visibility
|
|
29
|
+
* (`[sanity-workbench:os:remotes]`) — boot does not gate on it.
|
|
30
|
+
*
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export const remotesLogic = setup({
|
|
34
|
+
types: {
|
|
35
|
+
input: {} as RemotesInput,
|
|
36
|
+
context: {} as RemotesContext,
|
|
37
|
+
events: {} as RemotesEvent,
|
|
38
|
+
},
|
|
39
|
+
actors: {
|
|
40
|
+
remote: remoteLogic,
|
|
41
|
+
},
|
|
42
|
+
guards: {
|
|
43
|
+
remoteNotKnown: ({ context }, params: { moduleId: string }) =>
|
|
44
|
+
!context.children.has(params.moduleId),
|
|
45
|
+
},
|
|
46
|
+
actions: {
|
|
47
|
+
spawnRemote: assign({
|
|
48
|
+
children: (
|
|
49
|
+
{ context, spawn },
|
|
50
|
+
params: { moduleId: string; entry: string },
|
|
51
|
+
) => {
|
|
52
|
+
const ref = spawn("remote", {
|
|
53
|
+
id: params.moduleId,
|
|
54
|
+
systemId: `remotes.${params.moduleId}`,
|
|
55
|
+
input: {
|
|
56
|
+
moduleId: params.moduleId,
|
|
57
|
+
entry: params.entry,
|
|
58
|
+
instance: context.instance,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
return new Map(context.children).set(params.moduleId, ref);
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
}).createMachine({
|
|
66
|
+
id: "remotes",
|
|
67
|
+
context: ({ input }) => ({
|
|
68
|
+
instance: input.instance,
|
|
69
|
+
children: new Map(),
|
|
70
|
+
}),
|
|
71
|
+
on: {
|
|
72
|
+
"remote.load.request": {
|
|
73
|
+
guard: {
|
|
74
|
+
type: "remoteNotKnown",
|
|
75
|
+
params: ({ event }) => ({ moduleId: event.moduleId }),
|
|
76
|
+
},
|
|
77
|
+
actions: [
|
|
78
|
+
{
|
|
79
|
+
type: "spawnRemote",
|
|
80
|
+
params: ({ event }) => ({
|
|
81
|
+
moduleId: event.moduleId,
|
|
82
|
+
entry: event.entry,
|
|
83
|
+
}),
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
// Reserved for future supervision/retry. Forwarded by per-remote
|
|
88
|
+
// children on entry to `loaded` or `error`; currently a no-op so the
|
|
89
|
+
// event is part of the typed surface rather than a silent unknown.
|
|
90
|
+
"remote.settled": {},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { createSanityInstance, type SanityInstance } from "@sanity/sdk";
|
|
2
|
+
import { raise, sendTo, setup, type ActorOptions } from "xstate";
|
|
3
|
+
|
|
4
|
+
import { logger } from "../core/log";
|
|
5
|
+
import { authLogic } from "./auth.machine";
|
|
6
|
+
import { inspect } from "./inspect";
|
|
7
|
+
import {
|
|
8
|
+
createInstance,
|
|
9
|
+
type FederationInstance,
|
|
10
|
+
log,
|
|
11
|
+
} from "./module-federation";
|
|
12
|
+
import { remotesLogic } from "./remotes.machine";
|
|
13
|
+
import { servicesLogic } from "./services.machine";
|
|
14
|
+
import {
|
|
15
|
+
type SystemPreferencesAdapter,
|
|
16
|
+
systemPreferencesLogic,
|
|
17
|
+
} from "./system-preferences.machine";
|
|
18
|
+
import {
|
|
19
|
+
telemetryLogic,
|
|
20
|
+
type WorkbenchUserProperties,
|
|
21
|
+
} from "./telemetry.machine";
|
|
22
|
+
|
|
23
|
+
type OSInput = WorkbenchUserProperties & {
|
|
24
|
+
systemPreferencesAdapter?: SystemPreferencesAdapter;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type OSContext = {
|
|
28
|
+
instance: SanityInstance;
|
|
29
|
+
/**
|
|
30
|
+
* The single module-federation instance every interface loads through —
|
|
31
|
+
* shared by the `remotes` (views) and `services` (workers) supervisors so an
|
|
32
|
+
* app's remote is registered once for all its interfaces.
|
|
33
|
+
*/
|
|
34
|
+
federationInstance: FederationInstance;
|
|
35
|
+
userProperties: WorkbenchUserProperties;
|
|
36
|
+
systemPreferencesAdapter: SystemPreferencesAdapter | undefined;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The base inputs for the OS machine.
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export interface OSBaseInput extends Pick<OSContext, "instance"> {}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The sanity OS machine, responsible for managing the global state of the OS.
|
|
47
|
+
* @public
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { os, createOSOptions } from "@sanity/workbench/system";
|
|
51
|
+
* import { useActor } from "@xstate/react";
|
|
52
|
+
*
|
|
53
|
+
* const [state, send] = useActor(os, createOSOptions({
|
|
54
|
+
* version: "1.0.0",
|
|
55
|
+
* organizationId: "...",
|
|
56
|
+
* environment: "production",
|
|
57
|
+
* userAgent: navigator.userAgent,
|
|
58
|
+
* }));
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export const os = setup({
|
|
62
|
+
types: {
|
|
63
|
+
input: {} as OSInput,
|
|
64
|
+
context: {} as OSContext,
|
|
65
|
+
events: {} as
|
|
66
|
+
| { type: "boot.auth.ready" }
|
|
67
|
+
| { type: "boot.auth.failed" }
|
|
68
|
+
| { type: "boot.telemetry.ready" },
|
|
69
|
+
// https://github.com/statelyai/xstate/issues/5515
|
|
70
|
+
children: {} as {
|
|
71
|
+
auth: "auth";
|
|
72
|
+
telemetry: "telemetry";
|
|
73
|
+
"system-preferences": "systemPreferences";
|
|
74
|
+
remotes: "remotes";
|
|
75
|
+
services: "services";
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
actors: {
|
|
79
|
+
auth: authLogic,
|
|
80
|
+
telemetry: telemetryLogic,
|
|
81
|
+
systemPreferences: systemPreferencesLogic,
|
|
82
|
+
remotes: remotesLogic,
|
|
83
|
+
services: servicesLogic,
|
|
84
|
+
},
|
|
85
|
+
guards: {
|
|
86
|
+
hasTag: (_, params: { hasTag: boolean }) => params.hasTag,
|
|
87
|
+
},
|
|
88
|
+
actions: {
|
|
89
|
+
raiseAuthReady: raise({ type: "boot.auth.ready" }),
|
|
90
|
+
raiseAuthFailed: raise({ type: "boot.auth.failed" }),
|
|
91
|
+
raiseTelemetryReady: raise({
|
|
92
|
+
type: "boot.telemetry.ready",
|
|
93
|
+
}),
|
|
94
|
+
startTelemetry: sendTo("telemetry", {
|
|
95
|
+
type: "telemetry.start",
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
}).createMachine({
|
|
99
|
+
id: "os",
|
|
100
|
+
context: ({ input }) => ({
|
|
101
|
+
instance: createSanityInstance(),
|
|
102
|
+
federationInstance: createInstance({
|
|
103
|
+
name: "workbench-applications",
|
|
104
|
+
plugins: [log(logger.debug)],
|
|
105
|
+
}),
|
|
106
|
+
userProperties: {
|
|
107
|
+
version: input.version,
|
|
108
|
+
organizationId: input.organizationId,
|
|
109
|
+
environment: input.environment,
|
|
110
|
+
userAgent: input.userAgent,
|
|
111
|
+
},
|
|
112
|
+
systemPreferencesAdapter: input.systemPreferencesAdapter,
|
|
113
|
+
}),
|
|
114
|
+
initial: "booting",
|
|
115
|
+
invoke: [
|
|
116
|
+
{
|
|
117
|
+
id: "auth",
|
|
118
|
+
systemId: "auth",
|
|
119
|
+
src: "auth",
|
|
120
|
+
input: ({ context }) => ({ instance: context.instance }),
|
|
121
|
+
onSnapshot: [
|
|
122
|
+
{
|
|
123
|
+
guard: {
|
|
124
|
+
type: "hasTag",
|
|
125
|
+
params: ({ event }) => ({
|
|
126
|
+
hasTag: event.snapshot.hasTag("authenticated"),
|
|
127
|
+
}),
|
|
128
|
+
},
|
|
129
|
+
actions: [{ type: "raiseAuthReady" }],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
guard: {
|
|
133
|
+
type: "hasTag",
|
|
134
|
+
params: ({ event }) => ({
|
|
135
|
+
hasTag: event.snapshot.hasTag("error"),
|
|
136
|
+
}),
|
|
137
|
+
},
|
|
138
|
+
actions: [{ type: "raiseAuthFailed" }],
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: "telemetry",
|
|
144
|
+
systemId: "telemetry",
|
|
145
|
+
src: "telemetry",
|
|
146
|
+
input: ({ context }) => ({
|
|
147
|
+
instance: context.instance,
|
|
148
|
+
...context.userProperties,
|
|
149
|
+
}),
|
|
150
|
+
onSnapshot: [
|
|
151
|
+
{
|
|
152
|
+
guard: {
|
|
153
|
+
type: "hasTag",
|
|
154
|
+
params: ({ event }) => ({
|
|
155
|
+
hasTag: event.snapshot.hasTag("telemetry-resolved"),
|
|
156
|
+
}),
|
|
157
|
+
},
|
|
158
|
+
actions: [{ type: "raiseTelemetryReady" }],
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "system-preferences",
|
|
164
|
+
systemId: "system-preferences",
|
|
165
|
+
src: "systemPreferences",
|
|
166
|
+
input: ({ context }) => ({ adapter: context.systemPreferencesAdapter }),
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "remotes",
|
|
170
|
+
systemId: "remotes",
|
|
171
|
+
src: "remotes",
|
|
172
|
+
input: ({ context }) => ({ instance: context.federationInstance }),
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: "services",
|
|
176
|
+
systemId: "services",
|
|
177
|
+
src: "services",
|
|
178
|
+
input: ({ context }) => ({ instance: context.federationInstance }),
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
states: {
|
|
182
|
+
booting: {
|
|
183
|
+
initial: "auth",
|
|
184
|
+
states: {
|
|
185
|
+
auth: {
|
|
186
|
+
on: {
|
|
187
|
+
"boot.auth.ready": {
|
|
188
|
+
target: "telemetry",
|
|
189
|
+
actions: [{ type: "startTelemetry" }],
|
|
190
|
+
},
|
|
191
|
+
"boot.auth.failed": { target: "error" },
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
telemetry: {
|
|
195
|
+
on: {
|
|
196
|
+
"boot.telemetry.ready": { target: "done" },
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
error: {},
|
|
200
|
+
done: { type: "final" },
|
|
201
|
+
},
|
|
202
|
+
onDone: { target: "running" },
|
|
203
|
+
},
|
|
204
|
+
running: {
|
|
205
|
+
type: "parallel",
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Creates a set of default options for the OS machine. Forwards the workbench
|
|
212
|
+
* user properties to the machine's input and wires the structured-logging
|
|
213
|
+
* `inspect` callback. Browser-specific concerns (color-scheme seeding,
|
|
214
|
+
* persistence) live in the {@link SystemPreferencesAdapter} the host passes
|
|
215
|
+
* via `systemPreferencesAdapter`.
|
|
216
|
+
* @public
|
|
217
|
+
*/
|
|
218
|
+
export function createOSOptions(input: OSInput) {
|
|
219
|
+
return {
|
|
220
|
+
id: "os",
|
|
221
|
+
input,
|
|
222
|
+
inspect,
|
|
223
|
+
} satisfies ActorOptions<typeof os>;
|
|
224
|
+
}
|