@sanity/workbench 0.1.0-alpha.11 → 0.1.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/system.js ADDED
@@ -0,0 +1,436 @@
1
+ import { getAuthState, logout, AuthStateType, getClient, createSanityInstance } from "@sanity/sdk";
2
+ import { fromObservable, fromPromise, setup, assign, sendTo, raise } from "xstate";
3
+ import "./_chunks-es/studio.js";
4
+ import { logger } from "./_chunks-es/index.js";
5
+ import { createSessionId, createBatchedStore } from "@sanity/telemetry";
6
+ const authStateLogic = fromObservable(
7
+ ({ input }) => getAuthState(input.instance).observable
8
+ ), logoutActorLogic = fromPromise(async ({ input }) => {
9
+ await logout(input.instance);
10
+ }), authLogic = setup({
11
+ types: {
12
+ input: {},
13
+ context: {},
14
+ events: {},
15
+ tags: {}
16
+ },
17
+ actors: {
18
+ authState: authStateLogic,
19
+ logoutActor: logoutActorLogic
20
+ },
21
+ delays: {
22
+ authTimeout: 3e4
23
+ },
24
+ guards: {
25
+ isLoggedInComplete: (_, params) => params.state?.type === AuthStateType.LOGGED_IN && !!params.state.token && params.state.currentUser !== null,
26
+ isAuthState: (_, params) => params.state?.type === params.type
27
+ },
28
+ actions: {
29
+ setLoggedIn: assign({
30
+ token: (_, params) => params.token,
31
+ currentUser: (_, params) => params.currentUser,
32
+ error: () => null
33
+ }),
34
+ clearAuth: assign({
35
+ token: () => null,
36
+ currentUser: () => null,
37
+ error: () => null
38
+ }),
39
+ setError: assign({
40
+ token: () => null,
41
+ currentUser: () => null,
42
+ error: (_, params) => params.error
43
+ })
44
+ }
45
+ }).createMachine({
46
+ id: "auth",
47
+ initial: "init",
48
+ context: ({ input }) => ({
49
+ instance: input.instance,
50
+ token: null,
51
+ currentUser: null,
52
+ error: null
53
+ }),
54
+ invoke: {
55
+ src: "authState",
56
+ input: ({ context }) => ({ instance: context.instance }),
57
+ onSnapshot: [
58
+ {
59
+ guard: {
60
+ type: "isLoggedInComplete",
61
+ params: ({ event }) => ({
62
+ state: event.snapshot.context
63
+ })
64
+ },
65
+ actions: [
66
+ {
67
+ type: "setLoggedIn",
68
+ params: ({ event }) => {
69
+ const state = event.snapshot.context;
70
+ return {
71
+ token: state.token,
72
+ currentUser: state.currentUser
73
+ };
74
+ }
75
+ }
76
+ ],
77
+ target: `.${AuthStateType.LOGGED_IN}`
78
+ },
79
+ {
80
+ guard: {
81
+ type: "isAuthState",
82
+ params: ({ event }) => ({
83
+ state: event.snapshot.context,
84
+ type: AuthStateType.LOGGING_IN
85
+ })
86
+ },
87
+ actions: [{ type: "clearAuth" }],
88
+ target: `.${AuthStateType.LOGGING_IN}`
89
+ },
90
+ {
91
+ guard: {
92
+ type: "isAuthState",
93
+ params: ({ event }) => ({
94
+ state: event.snapshot.context,
95
+ type: AuthStateType.ERROR
96
+ })
97
+ },
98
+ actions: [
99
+ {
100
+ type: "setError",
101
+ params: ({ event }) => ({
102
+ error: event.snapshot.context?.type === AuthStateType.ERROR ? event.snapshot.context.error : null
103
+ })
104
+ }
105
+ ],
106
+ target: `.${AuthStateType.ERROR}`
107
+ },
108
+ {
109
+ guard: {
110
+ type: "isAuthState",
111
+ params: ({ event }) => ({
112
+ state: event.snapshot.context,
113
+ type: AuthStateType.LOGGED_OUT
114
+ })
115
+ },
116
+ actions: [{ type: "clearAuth" }],
117
+ target: `.${AuthStateType.LOGGED_OUT}`
118
+ }
119
+ ]
120
+ },
121
+ states: {
122
+ init: {
123
+ tags: ["authenticating"],
124
+ after: {
125
+ authTimeout: {
126
+ actions: [
127
+ {
128
+ type: "setError",
129
+ params: () => ({
130
+ error: new Error("Authentication timed out")
131
+ })
132
+ }
133
+ ],
134
+ target: AuthStateType.ERROR
135
+ }
136
+ }
137
+ },
138
+ [AuthStateType.LOGGING_IN]: {
139
+ tags: ["authenticating"],
140
+ after: {
141
+ authTimeout: {
142
+ actions: [
143
+ {
144
+ type: "setError",
145
+ params: () => ({
146
+ error: new Error("Authentication timed out")
147
+ })
148
+ }
149
+ ],
150
+ target: AuthStateType.ERROR
151
+ }
152
+ }
153
+ },
154
+ [AuthStateType.LOGGED_IN]: {
155
+ tags: ["authenticated"],
156
+ on: {
157
+ "auth.logout": { target: "logging-out" }
158
+ }
159
+ },
160
+ "logging-out": {
161
+ invoke: {
162
+ src: "logoutActor",
163
+ input: ({ context }) => ({ instance: context.instance }),
164
+ onDone: {
165
+ target: AuthStateType.LOGGED_OUT
166
+ },
167
+ onError: {
168
+ actions: [
169
+ {
170
+ type: "setError",
171
+ params: ({ event }) => ({ error: event.error })
172
+ }
173
+ ],
174
+ target: AuthStateType.ERROR
175
+ }
176
+ }
177
+ },
178
+ [AuthStateType.LOGGED_OUT]: {},
179
+ [AuthStateType.ERROR]: { tags: ["error"] }
180
+ }
181
+ }), actorPath = (ref) => {
182
+ const segments = [];
183
+ let current = ref;
184
+ for (; current; )
185
+ segments.unshift(current.id ?? current.sessionId), current = current._parent;
186
+ return segments.join(":");
187
+ }, inspect = (event) => {
188
+ const ref = event.actorRef, log = logger.child(actorPath(ref));
189
+ switch (event.type) {
190
+ case "@xstate.snapshot": {
191
+ log.debug("snapshot", event.snapshot);
192
+ break;
193
+ }
194
+ case "@xstate.event":
195
+ log.debug("event", event.event);
196
+ break;
197
+ case "@xstate.action":
198
+ log.debug("action", event.action);
199
+ break;
200
+ }
201
+ }, TELEMETRY_API_VERSION = "2024-11-12", FLUSH_INTERVAL_MS = 3e4, checkConsentLogic = fromPromise(async ({ input, signal }) => {
202
+ try {
203
+ return await getClient(input.instance, {
204
+ apiVersion: TELEMETRY_API_VERSION
205
+ }).request({
206
+ uri: "/intake/telemetry-status",
207
+ tag: "telemetry-consent",
208
+ signal
209
+ });
210
+ } catch {
211
+ return { status: "undetermined" };
212
+ }
213
+ }), telemetryLogic = setup({
214
+ types: {
215
+ input: {},
216
+ context: {},
217
+ events: {}
218
+ },
219
+ actors: {
220
+ checkConsent: checkConsentLogic
221
+ },
222
+ guards: {
223
+ isConsentGranted: (_, params) => params.status === "granted"
224
+ },
225
+ actions: {
226
+ createStore: assign({
227
+ store: ({ context }) => {
228
+ const sessionId = createSessionId(), client = getClient(context.instance, {
229
+ apiVersion: TELEMETRY_API_VERSION
230
+ }), store = createBatchedStore(sessionId, {
231
+ flushInterval: FLUSH_INTERVAL_MS,
232
+ resolveConsent: () => client.request({
233
+ uri: "/intake/telemetry-status",
234
+ tag: "telemetry-consent"
235
+ }),
236
+ sendEvents: (batch) => client.request({
237
+ uri: "/intake/batch",
238
+ method: "POST",
239
+ body: { batch },
240
+ tag: "telemetry.batch"
241
+ }),
242
+ sendBeacon: (batch) => typeof navigator > "u" ? !1 : navigator.sendBeacon(
243
+ client.getUrl("/intake/batch"),
244
+ JSON.stringify({ batch })
245
+ )
246
+ });
247
+ return store.logger.updateUserProperties(context.userProperties), store;
248
+ }
249
+ }),
250
+ teardownStore: ({ context }) => {
251
+ context.store?.end();
252
+ }
253
+ }
254
+ }).createMachine({
255
+ id: "telemetry",
256
+ initial: "idle",
257
+ context: ({ input }) => ({
258
+ instance: input.instance,
259
+ store: null,
260
+ userProperties: {
261
+ version: input.version,
262
+ organizationId: input.organizationId,
263
+ environment: input.environment,
264
+ userAgent: input.userAgent
265
+ }
266
+ }),
267
+ states: {
268
+ idle: {
269
+ on: {
270
+ "telemetry.start": {
271
+ target: "checkingConsent"
272
+ }
273
+ }
274
+ },
275
+ checkingConsent: {
276
+ invoke: {
277
+ src: "checkConsent",
278
+ input: ({ context }) => ({
279
+ instance: context.instance
280
+ }),
281
+ onDone: [
282
+ {
283
+ guard: {
284
+ type: "isConsentGranted",
285
+ params: ({ event }) => ({
286
+ status: event.output.status
287
+ })
288
+ },
289
+ actions: [{ type: "createStore" }],
290
+ target: "active"
291
+ },
292
+ {
293
+ target: "denied"
294
+ }
295
+ ]
296
+ }
297
+ },
298
+ active: {
299
+ tags: ["telemetry-resolved"],
300
+ exit: [{ type: "teardownStore" }],
301
+ on: {
302
+ "telemetry.stop": { target: "stopped" }
303
+ }
304
+ },
305
+ stopped: {
306
+ type: "final"
307
+ },
308
+ denied: {
309
+ tags: ["telemetry-resolved"]
310
+ }
311
+ }
312
+ }), os = setup({
313
+ types: {
314
+ input: {},
315
+ context: {},
316
+ events: {},
317
+ // https://github.com/statelyai/xstate/issues/5515
318
+ children: {}
319
+ },
320
+ actors: {
321
+ auth: authLogic,
322
+ telemetry: telemetryLogic
323
+ },
324
+ guards: {
325
+ hasTag: (_, params) => params.hasTag
326
+ },
327
+ actions: {
328
+ raiseAuthReady: raise({ type: "boot.auth.ready" }),
329
+ raiseAuthFailed: raise({ type: "boot.auth.failed" }),
330
+ raiseTelemetryReady: raise({
331
+ type: "boot.telemetry.ready"
332
+ }),
333
+ startTelemetry: sendTo("telemetry", {
334
+ type: "telemetry.start"
335
+ })
336
+ }
337
+ }).createMachine({
338
+ id: "os",
339
+ context: ({ input }) => ({
340
+ instance: createSanityInstance(),
341
+ userProperties: {
342
+ version: input.version,
343
+ organizationId: input.organizationId,
344
+ environment: input.environment,
345
+ userAgent: input.userAgent
346
+ }
347
+ }),
348
+ initial: "booting",
349
+ invoke: [
350
+ {
351
+ id: "auth",
352
+ systemId: "auth",
353
+ src: "auth",
354
+ input: ({ context }) => ({ instance: context.instance }),
355
+ onSnapshot: [
356
+ {
357
+ guard: {
358
+ type: "hasTag",
359
+ params: ({ event }) => ({
360
+ hasTag: event.snapshot.hasTag("authenticated")
361
+ })
362
+ },
363
+ actions: [{ type: "raiseAuthReady" }]
364
+ },
365
+ {
366
+ guard: {
367
+ type: "hasTag",
368
+ params: ({ event }) => ({
369
+ hasTag: event.snapshot.hasTag("error")
370
+ })
371
+ },
372
+ actions: [{ type: "raiseAuthFailed" }]
373
+ }
374
+ ]
375
+ },
376
+ {
377
+ id: "telemetry",
378
+ systemId: "telemetry",
379
+ src: "telemetry",
380
+ input: ({ context }) => ({
381
+ instance: context.instance,
382
+ ...context.userProperties
383
+ }),
384
+ onSnapshot: [
385
+ {
386
+ guard: {
387
+ type: "hasTag",
388
+ params: ({ event }) => ({
389
+ hasTag: event.snapshot.hasTag("telemetry-resolved")
390
+ })
391
+ },
392
+ actions: [{ type: "raiseTelemetryReady" }]
393
+ }
394
+ ]
395
+ }
396
+ ],
397
+ states: {
398
+ booting: {
399
+ initial: "auth",
400
+ states: {
401
+ auth: {
402
+ on: {
403
+ "boot.auth.ready": {
404
+ target: "telemetry",
405
+ actions: [{ type: "startTelemetry" }]
406
+ },
407
+ "boot.auth.failed": { target: "error" }
408
+ }
409
+ },
410
+ telemetry: {
411
+ on: {
412
+ "boot.telemetry.ready": { target: "done" }
413
+ }
414
+ },
415
+ error: {},
416
+ done: { type: "final" }
417
+ },
418
+ onDone: { target: "running" }
419
+ },
420
+ running: {
421
+ type: "parallel"
422
+ }
423
+ }
424
+ });
425
+ function createOSOptions(input) {
426
+ return {
427
+ id: "os",
428
+ input,
429
+ inspect
430
+ };
431
+ }
432
+ export {
433
+ createOSOptions,
434
+ os
435
+ };
436
+ //# sourceMappingURL=system.js.map
@@ -0,0 +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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/workbench",
3
- "version": "0.1.0-alpha.11",
3
+ "version": "0.1.0-alpha.13",
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",
@@ -34,23 +34,34 @@
34
34
  "development": "./src/_exports/core.ts",
35
35
  "default": "./dist/core.js"
36
36
  },
37
+ "./system": {
38
+ "source": "./src/_exports/system.ts",
39
+ "development": "./src/_exports/system.ts",
40
+ "default": "./dist/system.js"
41
+ },
37
42
  "./package.json": "./package.json"
38
43
  },
39
44
  "dependencies": {
40
45
  "@sanity/message-protocol": "^0.23.0",
46
+ "@sanity/telemetry": "^1.1.0",
41
47
  "rxjs": "^7.8.2",
42
48
  "semver": "^7.7.4",
49
+ "xstate": "^5.31.0",
43
50
  "zod": "^4.3.6",
44
51
  "@sanity/federation": "0.1.0-alpha.7"
45
52
  },
46
53
  "devDependencies": {
47
54
  "@sanity/pkg-utils": "^9.2.3",
55
+ "@sanity/sdk": "https://pkg.pr.new/sanity-io/sdk/@sanity/sdk@fbc9e08",
48
56
  "@types/semver": "^7.7.1",
49
57
  "typescript": "^6.0.2",
50
58
  "vite": "^7.3.1",
51
59
  "@repo/tsconfig": "0.0.1",
52
60
  "@repo/oxc-config": "0.0.0"
53
61
  },
62
+ "peerDependencies": {
63
+ "@sanity/sdk": "^2.9.0"
64
+ },
54
65
  "browserslist": "extends @sanity/browserslist-config",
55
66
  "engines": {
56
67
  "node": ">=20.19.1 <22 || >=22.12"
@@ -0,0 +1 @@
1
+ export * from "../system";
@@ -26,6 +26,7 @@ export interface Logger {
26
26
  warn: (message: string, context?: LogContext) => void;
27
27
  info: (message: string, context?: LogContext) => void;
28
28
  debug: (message: string, context?: LogContext) => void;
29
+ child: (domain: string, context?: LogContext) => Logger;
29
30
  }
30
31
 
31
32
  const LEVELS: readonly LogLevel[] = ["none", "error", "warn", "info", "debug"];
@@ -37,6 +38,31 @@ interface LoggerOptions {
37
38
  }
38
39
 
39
40
  /**
41
+ * Creates a leveled logger with an optional namespace prefix and bound
42
+ * context. Calls below the configured `logLevel` are suppressed; `"none"`
43
+ * silences the logger entirely.
44
+ *
45
+ * Use {@link Logger.child} to derive a sub-logger with an extended namespace
46
+ * (e.g. `parent:domain`) that inherits the parent's level and merges its
47
+ * bound context.
48
+ *
49
+ * @param options - Logger configuration.
50
+ * @param options.namespace - Prepended to every message in `[brackets]`.
51
+ * @param options.context - Bound context merged with per-call context.
52
+ * Per-call keys win on conflict.
53
+ * @param options.logLevel - Maximum verbosity to emit. Default `"info"`.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const log = createLogger({ namespace: "checkout", logLevel: "debug" });
58
+ * log.info("placed", { orderId: "abc" });
59
+ * // → [checkout] placed { orderId: "abc" }
60
+ *
61
+ * const auth = log.child("auth", { tenant: "acme" });
62
+ * auth.warn("token expiring");
63
+ * // → [checkout:auth] token expiring { tenant: "acme" }
64
+ * ```
65
+ *
40
66
  * @public
41
67
  */
42
68
  export function createLogger({
@@ -76,6 +102,13 @@ export function createLogger({
76
102
  warn: (message, context) => logAtLevel("warn", message, context),
77
103
  info: (message, context) => logAtLevel("info", message, context),
78
104
  debug: (message, context) => logAtLevel("debug", message, context),
105
+ child: (domain, context) =>
106
+ createLogger({
107
+ logLevel,
108
+ namespace: namespace ? `${namespace}:${domain}` : domain,
109
+ context:
110
+ baseContext || context ? { ...baseContext, ...context } : undefined,
111
+ }),
79
112
  };
80
113
  }
81
114
 
@@ -57,7 +57,7 @@ export const Project = z.object({
57
57
  externalStudioHost: z.string().optional(),
58
58
  initialTemplate: z.string().optional(),
59
59
  cliInitializedAt: z.string().optional(),
60
- integration: z.literal(["manage", "cli"]),
60
+ integration: z.string().optional(),
61
61
  }),
62
62
  isBlocked: z.boolean(),
63
63
  isDisabled: z.boolean(),
@@ -29,19 +29,22 @@ const CoreAppUserApplicationBase = UserApplicationBase.extend({
29
29
  title: z.string(),
30
30
  organizationId: OrganizationId,
31
31
  type: z.literal("coreApp"),
32
- manifest: CoreAppUserApplicationManifest.nullable().optional(),
33
32
  });
34
33
 
34
+ // Core apps surface their manifest exclusively via `activeDeployment.manifest`
35
+ // — they have no top-level `manifest` field and no `manifestData`.
36
+ const CoreAppActiveDeployment = ActiveDeployment.extend({
37
+ manifest: CoreAppUserApplicationManifest.nullable(),
38
+ }).nullable();
39
+
35
40
  const InternalCoreAppUserApplication = CoreAppUserApplicationBase.extend({
36
41
  urlType: z.literal("internal"),
37
- activeDeployment: ActiveDeployment.extend({
38
- manifest: CoreAppUserApplicationManifest.nullable().optional(),
39
- }).nullable(),
42
+ activeDeployment: CoreAppActiveDeployment,
40
43
  });
41
44
 
42
45
  const ExternalCoreAppUserApplication = CoreAppUserApplicationBase.extend({
43
46
  urlType: z.literal("external"),
44
- activeDeployment: z.null(),
47
+ activeDeployment: CoreAppActiveDeployment,
45
48
  });
46
49
 
47
50
  /**
@@ -98,7 +101,17 @@ export class CoreAppApplication extends UserApplication<
98
101
  }
99
102
 
100
103
  get title() {
101
- return this.activeDeployment?.manifest?.title ?? this.application.title;
104
+ return this.manifest?.title ?? this.application.title;
105
+ }
106
+
107
+ /**
108
+ * Resolves the core app's manifest from `activeDeployment.manifest`. This
109
+ * is the canonical (and only) slot for core app manifests — both for
110
+ * Sanity-deployed apps and for local CLI dev-server apps, which synthesise
111
+ * a deployment to surface the live manifest.
112
+ */
113
+ get manifest(): CoreAppUserApplicationManifest | null {
114
+ return this.activeDeployment?.manifest ?? null;
102
115
  }
103
116
 
104
117
  get subtitle() {
@@ -18,7 +18,10 @@ const Workspace = z.object({
18
18
  */
19
19
  export type Workspace = z.output<typeof Workspace>;
20
20
 
21
- const ServerManifest = z.object({
21
+ /**
22
+ * @public
23
+ */
24
+ export const ServerManifest = z.object({
22
25
  buildId: z.string().optional(),
23
26
  bundleVersion: z.string().optional(),
24
27
  version: z.string().optional(),
@@ -32,6 +35,11 @@ const ServerManifest = z.object({
32
35
  .optional(),
33
36
  });
34
37
 
38
+ /**
39
+ * @public
40
+ */
41
+ export type ServerManifest = z.output<typeof ServerManifest>;
42
+
35
43
  /**
36
44
  * @public
37
45
  */
@@ -56,6 +64,9 @@ const StudioUserApplicationBase = UserApplicationBase.extend({
56
64
  title: z.string().nullable(),
57
65
  projectId: ProjectId,
58
66
  type: z.literal("studio"),
67
+ /**
68
+ * @deprecated Use `manifestData` instead.
69
+ */
59
70
  manifest: ClientManifest.nullable(),
60
71
  manifestData: z.object({ value: ClientManifest }).nullable(),
61
72
  autoUpdatingVersion: z.string().nullable(),