@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.
Files changed (52) hide show
  1. package/README.md +24 -0
  2. package/dist/_chunks-es/index.js +39 -0
  3. package/dist/_chunks-es/index.js.map +1 -0
  4. package/dist/_chunks-es/module-federation.js +59 -0
  5. package/dist/_chunks-es/module-federation.js.map +1 -0
  6. package/dist/_chunks-es/studio.js +892 -0
  7. package/dist/_chunks-es/studio.js.map +1 -0
  8. package/dist/_internal.d.ts +16 -4
  9. package/dist/_internal.js +34 -27
  10. package/dist/_internal.js.map +1 -1
  11. package/dist/core.d.ts +2250 -0
  12. package/dist/core.js +74 -0
  13. package/dist/core.js.map +1 -0
  14. package/dist/system.d.ts +2135 -0
  15. package/dist/system.js +887 -0
  16. package/dist/system.js.map +1 -0
  17. package/package.json +34 -6
  18. package/src/_exports/core.ts +1 -0
  19. package/src/_exports/system.ts +1 -0
  20. package/src/_internal/index.ts +2 -1
  21. package/src/_internal/render.ts +72 -43
  22. package/src/core/applications/application-list.ts +104 -0
  23. package/src/core/applications/application.ts +177 -0
  24. package/src/core/applications/interface.ts +126 -0
  25. package/src/core/canvases.ts +92 -0
  26. package/src/core/config.ts +34 -0
  27. package/src/core/env.ts +43 -0
  28. package/src/core/index.ts +13 -0
  29. package/src/core/log/index.ts +125 -0
  30. package/src/core/media-libraries.ts +93 -0
  31. package/src/core/organizations.ts +115 -0
  32. package/src/core/projects.ts +114 -0
  33. package/src/core/shared/urls.ts +129 -0
  34. package/src/core/user-applications/core-app.ts +148 -0
  35. package/src/core/user-applications/studios/index.ts +3 -0
  36. package/src/core/user-applications/studios/schemas.ts +128 -0
  37. package/src/core/user-applications/studios/studio.ts +533 -0
  38. package/src/core/user-applications/studios/workspace.ts +156 -0
  39. package/src/core/user-applications/user-application.ts +222 -0
  40. package/src/system/auth.machine.ts +223 -0
  41. package/src/system/index.ts +22 -0
  42. package/src/system/inspect.ts +40 -0
  43. package/src/system/load-federated-module.ts +53 -0
  44. package/src/system/module-federation.ts +116 -0
  45. package/src/system/remote.machine.ts +219 -0
  46. package/src/system/remotes.machine.ts +92 -0
  47. package/src/system/root.machine.ts +224 -0
  48. package/src/system/service.machine.ts +207 -0
  49. package/src/system/services.machine.ts +120 -0
  50. package/src/system/system-preferences.machine.ts +215 -0
  51. package/src/system/telemetry.machine.ts +179 -0
  52. package/src/_internal/render.test.ts +0 -18
@@ -0,0 +1,179 @@
1
+ import { getClient, type SanityInstance } from "@sanity/sdk";
2
+ import {
3
+ type ConsentStatus,
4
+ createBatchedStore,
5
+ createSessionId,
6
+ type TelemetryEvent,
7
+ type TelemetryStore,
8
+ } from "@sanity/telemetry";
9
+ import { assign, fromPromise, setup } from "xstate";
10
+
11
+ import type { OSBaseInput } from "./root.machine";
12
+
13
+ /**
14
+ * @public
15
+ */
16
+ export type WorkbenchUserProperties = {
17
+ version: string;
18
+ organizationId: string;
19
+ environment: string;
20
+ userAgent: string;
21
+ };
22
+
23
+ /**
24
+ * @internal
25
+ */
26
+ export interface TelemetryInput extends OSBaseInput, WorkbenchUserProperties {}
27
+
28
+ /**
29
+ * TODO: this shouldn't be unique to the telemetry machine,
30
+ * remove this and set it globally with a single client actor.
31
+ */
32
+ const TELEMETRY_API_VERSION = "2024-11-12";
33
+ /**
34
+ * 30 seconds, in milliseconds, is the default flush interval
35
+ * for the telemetry store.
36
+ */
37
+ const FLUSH_INTERVAL_MS = 30_000;
38
+
39
+ type ConsentResult = { status: ConsentStatus };
40
+
41
+ const checkConsentLogic = fromPromise<
42
+ ConsentResult,
43
+ { instance: SanityInstance }
44
+ >(async ({ input, signal }) => {
45
+ try {
46
+ const client = getClient(input.instance, {
47
+ apiVersion: TELEMETRY_API_VERSION,
48
+ });
49
+ return await client.request<ConsentResult>({
50
+ uri: "/intake/telemetry-status",
51
+ tag: "telemetry-consent",
52
+ signal,
53
+ });
54
+ } catch {
55
+ return { status: "undetermined" } satisfies ConsentResult;
56
+ }
57
+ });
58
+
59
+ type TelemetryContext = {
60
+ instance: SanityInstance;
61
+ store: TelemetryStore<WorkbenchUserProperties> | null;
62
+ userProperties: WorkbenchUserProperties;
63
+ };
64
+
65
+ type TelemetryMachineEvent =
66
+ | { type: "telemetry.start" }
67
+ | { type: "telemetry.stop" };
68
+
69
+ export const telemetryLogic = setup({
70
+ types: {
71
+ input: {} as TelemetryInput,
72
+ context: {} as TelemetryContext,
73
+ events: {} as TelemetryMachineEvent,
74
+ },
75
+ actors: {
76
+ checkConsent: checkConsentLogic,
77
+ },
78
+ guards: {
79
+ isConsentGranted: (_, params: { status: ConsentStatus }) =>
80
+ params.status === "granted",
81
+ },
82
+ actions: {
83
+ createStore: assign({
84
+ store: ({ context }) => {
85
+ const sessionId = createSessionId();
86
+ const client = getClient(context.instance, {
87
+ apiVersion: TELEMETRY_API_VERSION,
88
+ });
89
+ const store = createBatchedStore<WorkbenchUserProperties>(sessionId, {
90
+ flushInterval: FLUSH_INTERVAL_MS,
91
+ resolveConsent: () =>
92
+ client.request<{ status: ConsentStatus }>({
93
+ uri: "/intake/telemetry-status",
94
+ tag: "telemetry-consent",
95
+ }),
96
+ sendEvents: (batch: TelemetryEvent[]) =>
97
+ client.request({
98
+ uri: "/intake/batch",
99
+ method: "POST",
100
+ body: { batch },
101
+ tag: "telemetry.batch",
102
+ }),
103
+ sendBeacon: (batch: TelemetryEvent[]) => {
104
+ if (typeof navigator === "undefined") {
105
+ return false;
106
+ }
107
+ return navigator.sendBeacon(
108
+ client.getUrl("/intake/batch"),
109
+ JSON.stringify({ batch }),
110
+ );
111
+ },
112
+ });
113
+ store.logger.updateUserProperties(context.userProperties);
114
+ return store;
115
+ },
116
+ }),
117
+ teardownStore: ({ context }) => {
118
+ context.store?.end();
119
+ },
120
+ },
121
+ }).createMachine({
122
+ id: "telemetry",
123
+ initial: "idle",
124
+ context: ({ input }) => ({
125
+ instance: input.instance,
126
+ store: null,
127
+ userProperties: {
128
+ version: input.version,
129
+ organizationId: input.organizationId,
130
+ environment: input.environment,
131
+ userAgent: input.userAgent,
132
+ },
133
+ }),
134
+ states: {
135
+ idle: {
136
+ on: {
137
+ "telemetry.start": {
138
+ target: "checkingConsent",
139
+ },
140
+ },
141
+ },
142
+ checkingConsent: {
143
+ invoke: {
144
+ src: "checkConsent",
145
+ input: ({ context }) => ({
146
+ instance: context.instance,
147
+ }),
148
+ onDone: [
149
+ {
150
+ guard: {
151
+ type: "isConsentGranted",
152
+ params: ({ event }) => ({
153
+ status: event.output.status,
154
+ }),
155
+ },
156
+ actions: [{ type: "createStore" }],
157
+ target: "active",
158
+ },
159
+ {
160
+ target: "denied",
161
+ },
162
+ ],
163
+ },
164
+ },
165
+ active: {
166
+ tags: ["telemetry-resolved"],
167
+ exit: [{ type: "teardownStore" }],
168
+ on: {
169
+ "telemetry.stop": { target: "stopped" },
170
+ },
171
+ },
172
+ stopped: {
173
+ type: "final",
174
+ },
175
+ denied: {
176
+ tags: ["telemetry-resolved"],
177
+ },
178
+ },
179
+ });
@@ -1,18 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import { renderWorkbench } from "./render";
4
-
5
- describe("renderWorkbench", () => {
6
- it("throws when rootElement is missing", async () => {
7
- await expect(
8
- renderWorkbench(null as unknown as HTMLElement),
9
- ).rejects.toThrow("Missing root element to mount application into");
10
- });
11
-
12
- it("throws when SANITY_INTERNAL_WORKBENCH_REMOTE_URL is not set", async () => {
13
- const el = document.createElement("div");
14
- await expect(renderWorkbench(el)).rejects.toThrow(
15
- "SANITY_INTERNAL_WORKBENCH_REMOTE_URL is not set",
16
- );
17
- });
18
- });