@sanity/workbench 0.1.0-alpha.7 → 0.1.0-alpha.9

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 (34) hide show
  1. package/dist/_chunks-es/index.js +6 -1
  2. package/dist/_chunks-es/index.js.map +1 -1
  3. package/dist/_internal.js +3 -8
  4. package/dist/_internal.js.map +1 -1
  5. package/dist/core.d.ts +582 -24
  6. package/dist/core.js +207 -105
  7. package/dist/core.js.map +1 -1
  8. package/package.json +9 -3
  9. package/src/_internal/render.ts +4 -11
  10. package/src/core/applications/application-list.ts +1 -1
  11. package/src/core/applications/local-application.ts +6 -2
  12. package/src/core/canvases.ts +1 -1
  13. package/src/core/index.ts +1 -1
  14. package/src/core/log/index.ts +12 -0
  15. package/src/core/media-libraries.ts +1 -1
  16. package/src/core/user-applications/core-app.ts +66 -10
  17. package/src/core/user-applications/studios/index.ts +3 -0
  18. package/src/core/user-applications/studios/schemas.ts +106 -0
  19. package/src/core/user-applications/{studio.ts → studios/studio.ts} +56 -214
  20. package/src/core/user-applications/studios/workspace.ts +143 -0
  21. package/src/core/user-applications/user-application.ts +36 -5
  22. package/src/_internal/render.test.ts +0 -73
  23. package/src/core/__tests__/__fixtures__.ts +0 -248
  24. package/src/core/applications/application-list.test.ts +0 -222
  25. package/src/core/applications/local-application.test.ts +0 -93
  26. package/src/core/canvases.test.ts +0 -38
  27. package/src/core/log/index.test.ts +0 -133
  28. package/src/core/media-libraries.test.ts +0 -38
  29. package/src/core/organizations.test.ts +0 -134
  30. package/src/core/projects.test.ts +0 -248
  31. package/src/core/shared/urls.test.ts +0 -182
  32. package/src/core/user-applications/core-app.test.ts +0 -151
  33. package/src/core/user-applications/studio.test.ts +0 -928
  34. package/src/core/user-applications/user-application.test.ts +0 -126
@@ -0,0 +1,106 @@
1
+ import { z } from "zod";
2
+
3
+ import { ProjectId } from "../../projects";
4
+ import { ActiveDeployment, UserApplicationBase } from "../user-application";
5
+
6
+ const Workspace = z.object({
7
+ name: z.string(),
8
+ title: z.string(),
9
+ subtitle: z.string().optional(),
10
+ basePath: z.string(),
11
+ projectId: ProjectId,
12
+ dataset: z.string().optional(),
13
+ icon: z.string().nullable().optional(),
14
+ });
15
+
16
+ /**
17
+ * @public
18
+ */
19
+ export type Workspace = z.output<typeof Workspace>;
20
+
21
+ const ServerManifest = z.object({
22
+ buildId: z.string().optional(),
23
+ bundleVersion: z.string().optional(),
24
+ version: z.string().optional(),
25
+ workspaces: z
26
+ .array(
27
+ Workspace.extend({
28
+ dataset: z.string(),
29
+ schemaDescriptorId: z.string(),
30
+ }),
31
+ )
32
+ .optional(),
33
+ });
34
+
35
+ /**
36
+ * @public
37
+ */
38
+ export const ClientManifest = z.object({
39
+ version: z.number(),
40
+ createdAt: z.string(),
41
+ studioVersion: z.string().optional(),
42
+ workspaces: z.array(
43
+ Workspace.extend({
44
+ schema: z.string(),
45
+ tools: z.string().optional(),
46
+ }),
47
+ ),
48
+ });
49
+
50
+ const StudioUserApplicationBase = UserApplicationBase.extend({
51
+ title: z.string().nullable(),
52
+ projectId: ProjectId,
53
+ type: z.literal("studio"),
54
+ manifest: ClientManifest.nullable(),
55
+ manifestData: z.object({ value: ClientManifest }).nullable(),
56
+ autoUpdatingVersion: z.string().nullable(),
57
+ config: z.object({
58
+ "live-manifest": z
59
+ .object({
60
+ createdAt: z.string(),
61
+ updatedAt: z.string(),
62
+ updatedBy: z.string(),
63
+ value: ServerManifest,
64
+ })
65
+ .optional(),
66
+ }),
67
+ });
68
+
69
+ const InternalStudioUserApplication = StudioUserApplicationBase.extend({
70
+ urlType: z.literal("internal"),
71
+ activeDeployment: ActiveDeployment.extend({
72
+ manifest: ServerManifest.nullable(),
73
+ }),
74
+ });
75
+
76
+ const ExternalStudioUserApplication = StudioUserApplicationBase.extend({
77
+ urlType: z.literal("external"),
78
+ activeDeployment: z.null(),
79
+ });
80
+
81
+ /**
82
+ * Studio user application schema — validates and brands API
83
+ * responses from the `/user-applications?appType=studio`
84
+ * endpoint. Uses a discriminated union on `urlType`.
85
+ * @public
86
+ */
87
+ export const StudioUserApplication = z.discriminatedUnion("urlType", [
88
+ InternalStudioUserApplication,
89
+ ExternalStudioUserApplication,
90
+ ]);
91
+
92
+ /**
93
+ * @public
94
+ */
95
+ export type StudioUserApplication = z.output<typeof StudioUserApplication>;
96
+
97
+ /**
98
+ * Validates and parses a raw API response into a branded
99
+ * StudioUserApplication.
100
+ * @public
101
+ */
102
+ export function parseStudioUserApplication(
103
+ data: unknown,
104
+ ): StudioUserApplication {
105
+ return StudioUserApplication.parse(data);
106
+ }
@@ -1,82 +1,52 @@
1
- import type {
2
- StudioApplication as StudioApplicationData,
3
- // eslint-disable-next-line no-restricted-imports
4
- StudioResource as ProtocolStudioResource,
5
- WorkspaceManifest,
6
- } from "@sanity/message-protocol";
7
1
  import type { SemVer } from "semver";
8
2
  import { coerce, gt, gte, lt, rsort, valid } from "semver";
9
- import { z } from "zod";
10
3
 
11
- import { AbstractApplication } from "../applications/application";
4
+ import { type Project } from "../../projects";
5
+ import { UserApplication } from "../user-application";
12
6
  import {
13
- brandProjectId,
14
- ProjectId as ProjectIdSchema,
15
- type Project,
16
- type ProjectId,
17
- } from "../projects";
18
- import { joinUrlPaths, normalizePath } from "../shared/urls";
19
- import { type UserApplicationId } from "./user-application";
20
- import { UserApplication } from "./user-application";
21
-
22
- const WORKSPACE_MANIFEST_SCHEMA = z.object({
23
- name: z.string(),
24
- title: z.string(),
25
- subtitle: z.string().nullable().optional(),
26
- basePath: z.string(),
27
- projectId: ProjectIdSchema,
28
- dataset: z.string(),
29
- icon: z.string().optional().nullable(),
30
- schema: z.string(),
31
- tools: z.string().optional(),
32
- });
33
-
34
- const STUDIO_MANIFEST_SCHEMA = z
35
- .object({
36
- // data from manifest
37
- version: z.number(),
38
- createdAt: z.string(),
39
- studioVersion: z.string().nullable().optional(),
40
- // data from workspace object
41
- workspaces: z.array(WORKSPACE_MANIFEST_SCHEMA),
42
- })
43
- .superRefine((data, ctx) => {
44
- if (!data.version) {
45
- ctx.addIssue({
46
- code: "invalid_type",
47
- message: "Manifest version is too old",
48
- expected: "number",
49
- });
50
- }
7
+ type Workspace,
8
+ type StudioUserApplication,
9
+ ClientManifest as ClientManifestSchema,
10
+ } from "./schemas";
11
+ import { StudioWorkspace } from "./workspace";
12
+
13
+ const ClientManifest = ClientManifestSchema.superRefine((data, ctx) => {
14
+ if (!data.version) {
15
+ ctx.addIssue({
16
+ code: "invalid_type",
17
+ message: "Manifest version is too old",
18
+ expected: "number",
19
+ });
20
+ }
51
21
 
52
- if (data.version < 2) {
53
- ctx.addIssue({
54
- code: "invalid_value",
55
- message: "Manifest version is too old",
56
- values: [2, 3],
57
- });
58
- }
22
+ if (data.version < 2) {
23
+ ctx.addIssue({
24
+ code: "invalid_value",
25
+ message: "Manifest version is too old",
26
+ values: [2, 3],
27
+ });
28
+ }
59
29
 
60
- if (data.version >= 3 && !data.studioVersion) {
61
- ctx.addIssue({
62
- code: "invalid_type",
63
- message: "Manifest version 3 or higher requires a `studioVersion`",
64
- expected: "string",
65
- });
66
- }
67
- });
30
+ if (data.version >= 3 && !data.studioVersion) {
31
+ ctx.addIssue({
32
+ code: "invalid_type",
33
+ message: "Manifest version 3 or higher requires a `studioVersion`",
34
+ expected: "string",
35
+ });
36
+ }
37
+ });
68
38
 
69
39
  const DEFAULT_WORKSPACE_DATA = {
70
40
  name: "default",
71
41
  title: "Default",
72
42
  basePath: "/",
73
- } as const satisfies Partial<Workspace>;
43
+ } as const satisfies Omit<Workspace, "projectId">;
74
44
 
75
45
  /**
76
46
  * @internal
77
47
  */
78
48
  export class StudioApplication extends UserApplication<
79
- StudioApplicationData,
49
+ StudioUserApplication,
80
50
  "studio",
81
51
  never
82
52
  > {
@@ -88,6 +58,14 @@ export class StudioApplication extends UserApplication<
88
58
 
89
59
  readonly project: Project<false, false>;
90
60
 
61
+ /**
62
+ * The projects actually referenced by this studio — the application's own
63
+ * project plus any project used by a workspace. Preserved so the instance
64
+ * can be re-constructed (e.g. by dock wrappers) without having to thread
65
+ * the full organization project list through again.
66
+ */
67
+ readonly projects: Project<false, false>[];
68
+
91
69
  /**
92
70
  * @param application - The studio application to create a list of workspaces for
93
71
  * @param projects - The projects available in the organization. It's not enough to just pass
@@ -95,7 +73,7 @@ export class StudioApplication extends UserApplication<
95
73
  * The workspaces may have different projects completely.
96
74
  */
97
75
  constructor(
98
- application: StudioApplicationData,
76
+ application: StudioUserApplication,
99
77
  projects: Project<false, false>[],
100
78
  ) {
101
79
  super(application, "studio");
@@ -113,7 +91,7 @@ export class StudioApplication extends UserApplication<
113
91
  * this could potentially crash the app. Instead we log a warning and return an empty array.
114
92
  */
115
93
  try {
116
- workspaces = STUDIO_MANIFEST_SCHEMA.parse(
94
+ workspaces = ClientManifest.parse(
117
95
  application.manifestData?.value,
118
96
  ).workspaces;
119
97
  } catch (error) {
@@ -148,10 +126,7 @@ export class StudioApplication extends UserApplication<
148
126
  Array.isArray(serverManifestWorkspaces) &&
149
127
  serverManifestWorkspaces.length
150
128
  ) {
151
- workspaces = serverManifestWorkspaces.map((w) => ({
152
- ...w,
153
- projectId: brandProjectId(w.projectId),
154
- }));
129
+ workspaces = serverManifestWorkspaces;
155
130
  }
156
131
  }
157
132
 
@@ -172,8 +147,7 @@ export class StudioApplication extends UserApplication<
172
147
  return acc;
173
148
  }, new Map<Workspace, Project<false, false>>());
174
149
 
175
- const brandedProjectId = brandProjectId(application.projectId);
176
- const project = projects.find((p) => p.id === brandedProjectId);
150
+ const project = projects.find((p) => p.id === application.projectId);
177
151
 
178
152
  if (!project) {
179
153
  throw new Error(`Project not found for application ${application.id}`);
@@ -186,7 +160,7 @@ export class StudioApplication extends UserApplication<
186
160
  workspacesWithProjectsMap.set(
187
161
  {
188
162
  ...DEFAULT_WORKSPACE_DATA,
189
- projectId: brandedProjectId,
163
+ projectId: application.projectId,
190
164
  } satisfies Workspace,
191
165
  project,
192
166
  );
@@ -210,6 +184,14 @@ export class StudioApplication extends UserApplication<
210
184
  );
211
185
 
212
186
  this.project = project;
187
+
188
+ // Collect only the projects actually referenced by this studio — the
189
+ // application's own project plus any project used by a workspace.
190
+ const usedProjects = new Set<Project<false, false>>([project]);
191
+ for (const workspace of this.workspaces) {
192
+ usedProjects.add(workspace.project);
193
+ }
194
+ this.projects = Array.from(usedProjects);
213
195
  }
214
196
 
215
197
  get href() {
@@ -236,9 +218,9 @@ export class StudioApplication extends UserApplication<
236
218
  return new URL(this.url).hostname;
237
219
  }
238
220
 
239
- get<TKey extends keyof StudioApplicationData>(
221
+ get<TKey extends keyof StudioUserApplication>(
240
222
  attr: TKey,
241
- ): StudioApplicationData[TKey] {
223
+ ): StudioUserApplication[TKey] {
242
224
  if (!(attr in this.application)) {
243
225
  throw new Error(
244
226
  `Attribute ${attr.toString()} does not exist on studio ${this.application.id}`,
@@ -514,143 +496,3 @@ type StudioIssues = Array<{
514
496
  id: StudioDashboardIssue;
515
497
  version?: string;
516
498
  }>;
517
-
518
- type Workspace = Omit<WorkspaceManifest, "dataset" | "schema" | "projectId"> & {
519
- projectId: ProjectId;
520
- dataset?: string;
521
- schema?: string;
522
- };
523
-
524
- /**
525
- * @internal
526
- */
527
- export class StudioWorkspace extends AbstractApplication<
528
- "workspace",
529
- ProtocolStudioResource
530
- > {
531
- /**
532
- * Workspaces always belong to a studio application.
533
- * They do not exist on their own & therefore can access
534
- * information about the studio they're in via this property.
535
- */
536
- private readonly studioApplication: StudioApplication;
537
- private readonly workspace: Workspace;
538
- readonly project: Project<false, false>;
539
- private readonly isDefaultWorkspace: boolean;
540
-
541
- constructor(
542
- studioApplication: StudioApplication,
543
- workspace: Workspace,
544
- project: Project<false, false>,
545
- isDefaultWorkspace: boolean,
546
- ) {
547
- super("workspace");
548
-
549
- this.studioApplication = studioApplication;
550
- this.workspace = workspace;
551
- this.project = project;
552
- this.isDefaultWorkspace = isDefaultWorkspace;
553
- }
554
-
555
- /**
556
- * The studio application that this workspace belongs to.
557
- */
558
- get studio() {
559
- return this.studioApplication;
560
- }
561
-
562
- get id() {
563
- return StudioWorkspace.makeId(this.studio.id, this.workspace.name);
564
- }
565
-
566
- get href() {
567
- return joinUrlPaths(this.studio.href, this.workspace.name);
568
- }
569
-
570
- get title() {
571
- /**
572
- * If there's no manifest we will have created a single workspace for the application.
573
- * In this circumstance we won't have a meaningful title, so instead we use the hostname of the appHost.
574
- */
575
- if (this.isDefaultWorkspace) {
576
- return this.project.displayName;
577
- }
578
-
579
- return this.workspace.title;
580
- }
581
-
582
- get subtitle() {
583
- if (this.isDefaultWorkspace) {
584
- const isValidAppHost = URL.canParse(this.studio.get("appHost"));
585
- const url = isValidAppHost
586
- ? new URL(this.studio.get("appHost"))
587
- : this.studio.url;
588
-
589
- return url.hostname;
590
- }
591
-
592
- return this.get("subtitle");
593
- }
594
-
595
- get<TKey extends Exclude<keyof Workspace, "id" | "icon" | "title">>(
596
- attr: TKey,
597
- ): Workspace[TKey] {
598
- return this.workspace[attr];
599
- }
600
-
601
- /**
602
- * With comlink, studio-applications were not considered applications at all, only workspaces. This is partially why
603
- * we create default workspaces when the application has no manifest or the manifest has no workspaces.
604
- *
605
- * Thereby, to create it we depend on a lot of information from the parent application even if it's duplicated across
606
- * different workspaces.
607
- */
608
- toProtocolResource(): ProtocolStudioResource {
609
- return {
610
- ...this.workspace,
611
- type: "studio",
612
- userApplicationId: this.studio.id,
613
- activeDeployment: this.studio.get("activeDeployment"),
614
- autoUpdatingVersion: this.studio.get("autoUpdatingVersion"),
615
- dashboardStatus: this.studio.get("dashboardStatus"),
616
- url: this.studio.url.toString(),
617
- href: this.href,
618
- id: this.id,
619
- hasManifest: true,
620
- hasSchema: Boolean(this.workspace.schema),
621
- manifest: this.studio.get("manifestData")?.value ?? null,
622
- updatedAt: this.studio.get("updatedAt"),
623
- version: this.studio.get("activeDeployment")?.version,
624
- urlType: this.studio.get("urlType"),
625
- config: this.studio.get("config"),
626
- } satisfies ProtocolStudioResource;
627
- }
628
-
629
- /**
630
- * @returns the URL to the workspace of a studio application.
631
- */
632
- get url(): URL {
633
- const studioUrl = new URL(this.studio.url);
634
- const normalizedUrlPath = normalizePath(studioUrl.pathname);
635
-
636
- let finalBasePath = normalizePath(this.get("basePath"));
637
-
638
- // the appHost may already contain the basepath for externally hosted studios
639
- // or embedded studios, so we deduplicate the segments
640
- if (finalBasePath.startsWith(normalizedUrlPath)) {
641
- finalBasePath = finalBasePath.slice(normalizedUrlPath.length);
642
- }
643
-
644
- studioUrl.pathname = joinUrlPaths(normalizedUrlPath, finalBasePath);
645
-
646
- return studioUrl;
647
- }
648
-
649
- static makeId(applicationId: UserApplicationId, workspaceName: string) {
650
- return `${applicationId}-${workspaceName}`;
651
- }
652
-
653
- static splitId(id: string): [string, string] {
654
- return id.split(new RegExp(/-(.*)/)).slice(0, 2) as [string, string];
655
- }
656
- }
@@ -0,0 +1,143 @@
1
+ import type { StudioResource as ProtocolStudioResource } from "@sanity/message-protocol";
2
+
3
+ import { AbstractApplication } from "../../applications/application";
4
+ import type { Project } from "../../projects";
5
+ import { joinUrlPaths, normalizePath } from "../../shared/urls";
6
+ import type { UserApplicationId } from "../user-application";
7
+ import type { Workspace } from "./schemas";
8
+ import type { StudioApplication } from "./studio";
9
+
10
+ /**
11
+ * @internal
12
+ */
13
+ export class StudioWorkspace extends AbstractApplication<
14
+ "workspace",
15
+ ProtocolStudioResource
16
+ > {
17
+ /**
18
+ * Workspaces always belong to a studio application.
19
+ * They do not exist on their own & therefore can access
20
+ * information about the studio they're in via this property.
21
+ */
22
+ private readonly studioApplication: StudioApplication;
23
+ private readonly workspace: Workspace;
24
+ readonly project: Project<false, false>;
25
+ private readonly isDefaultWorkspace: boolean;
26
+
27
+ constructor(
28
+ studioApplication: StudioApplication,
29
+ workspace: Workspace,
30
+ project: Project<false, false>,
31
+ isDefaultWorkspace: boolean,
32
+ ) {
33
+ super("workspace");
34
+
35
+ this.studioApplication = studioApplication;
36
+ this.workspace = workspace;
37
+ this.project = project;
38
+ this.isDefaultWorkspace = isDefaultWorkspace;
39
+ }
40
+
41
+ /**
42
+ * The studio application that this workspace belongs to.
43
+ */
44
+ get studio() {
45
+ return this.studioApplication;
46
+ }
47
+
48
+ get id() {
49
+ return StudioWorkspace.makeId(this.studio.id, this.workspace.name);
50
+ }
51
+
52
+ get href() {
53
+ return joinUrlPaths(this.studio.href, this.workspace.name);
54
+ }
55
+
56
+ get title() {
57
+ /**
58
+ * If there's no manifest we will have created a single workspace for the application.
59
+ * In this circumstance we won't have a meaningful title, so instead we use the hostname of the appHost.
60
+ */
61
+ if (this.isDefaultWorkspace) {
62
+ return this.project.displayName;
63
+ }
64
+
65
+ return this.workspace.title;
66
+ }
67
+
68
+ get subtitle() {
69
+ if (this.isDefaultWorkspace) {
70
+ const isValidAppHost = URL.canParse(this.studio.get("appHost"));
71
+ const url = isValidAppHost
72
+ ? new URL(this.studio.get("appHost"))
73
+ : this.studio.url;
74
+
75
+ return url.hostname;
76
+ }
77
+
78
+ return this.get("subtitle");
79
+ }
80
+
81
+ get<TKey extends Exclude<keyof Workspace, "id" | "icon" | "title">>(
82
+ attr: TKey,
83
+ ): Workspace[TKey] {
84
+ return this.workspace[attr];
85
+ }
86
+
87
+ /**
88
+ * With comlink, studio-applications were not considered applications at all, only workspaces. This is partially why
89
+ * we create default workspaces when the application has no manifest or the manifest has no workspaces.
90
+ *
91
+ * Thereby, to create it we depend on a lot of information from the parent application even if it's duplicated across
92
+ * different workspaces.
93
+ */
94
+ toProtocolResource(): ProtocolStudioResource {
95
+ return {
96
+ ...this.workspace,
97
+ type: "studio",
98
+ userApplicationId: this.studio.id,
99
+ activeDeployment: this.studio.get("activeDeployment"),
100
+ autoUpdatingVersion: this.studio.get("autoUpdatingVersion"),
101
+ dashboardStatus: this.studio.get("dashboardStatus"),
102
+ url: this.studio.url.toString(),
103
+ href: this.href,
104
+ id: this.id,
105
+ hasManifest: true,
106
+ hasSchema: Boolean("schema" in this.workspace && this.workspace.schema),
107
+ manifest: (this.studio.get("manifestData")?.value ??
108
+ null) as ProtocolStudioResource["manifest"],
109
+ updatedAt: this.studio.get("updatedAt"),
110
+ version: this.studio.get("activeDeployment")?.version,
111
+ urlType: this.studio.get("urlType"),
112
+ config: this.studio.get("config"),
113
+ } satisfies ProtocolStudioResource;
114
+ }
115
+
116
+ /**
117
+ * @returns the URL to the workspace of a studio application.
118
+ */
119
+ get url(): URL {
120
+ const studioUrl = new URL(this.studio.url);
121
+ const normalizedUrlPath = normalizePath(studioUrl.pathname);
122
+
123
+ let finalBasePath = normalizePath(this.get("basePath"));
124
+
125
+ // the appHost may already contain the basepath for externally hosted studios
126
+ // or embedded studios, so we deduplicate the segments
127
+ if (finalBasePath.startsWith(normalizedUrlPath)) {
128
+ finalBasePath = finalBasePath.slice(normalizedUrlPath.length);
129
+ }
130
+
131
+ studioUrl.pathname = joinUrlPaths(normalizedUrlPath, finalBasePath);
132
+
133
+ return studioUrl;
134
+ }
135
+
136
+ static makeId(applicationId: UserApplicationId, workspaceName: string) {
137
+ return `${applicationId}-${workspaceName}`;
138
+ }
139
+
140
+ static splitId(id: string): [string, string] {
141
+ return id.split(new RegExp(/-(.*)/)).slice(0, 2) as [string, string];
142
+ }
143
+ }
@@ -1,7 +1,5 @@
1
- import type {
2
- Resource as ProtocolResource,
3
- UserApplication as UserApplicationData,
4
- } from "@sanity/message-protocol";
1
+ // eslint-disable-next-line no-restricted-imports
2
+ import type { Resource as ProtocolResource } from "@sanity/message-protocol";
5
3
  import { z } from "zod";
6
4
 
7
5
  import {
@@ -32,11 +30,44 @@ export function brandUserApplicationId(id: string): UserApplicationId {
32
30
  return UserApplicationId.parse(id);
33
31
  }
34
32
 
33
+ /**
34
+ * @public
35
+ */
36
+ export const UserApplicationBase = z.object({
37
+ id: UserApplicationId,
38
+ appHost: z.string(),
39
+ urlType: z.enum(["internal", "external"]),
40
+ createdAt: z.string(),
41
+ updatedAt: z.string(),
42
+ dashboardStatus: z.enum(["default", "disabled"]),
43
+ });
44
+
45
+ /**
46
+ * @public
47
+ */
48
+ export type UserApplicationBase = z.output<typeof UserApplicationBase>;
49
+
50
+ /**
51
+ * @public
52
+ */
53
+ export const ActiveDeployment = z.object({
54
+ id: z.string(),
55
+ version: z.string(),
56
+ isActiveDeployment: z.boolean(),
57
+ userApplicationId: z.string(),
58
+ isAutoUpdating: z.boolean(),
59
+ size: z.number(),
60
+ deployedAt: z.string(),
61
+ deployedBy: z.string(),
62
+ createdAt: z.string(),
63
+ updatedAt: z.string(),
64
+ });
65
+
35
66
  /**
36
67
  * @internal
37
68
  */
38
69
  export abstract class UserApplication<
39
- TUserApplication extends UserApplicationData,
70
+ TUserApplication extends UserApplicationBase,
40
71
  TType extends Extract<AbstractApplicationType, "coreApp" | "studio">,
41
72
  TProtocolResource extends ProtocolResource = Extract<
42
73
  ProtocolResource,