@sanity/workbench-cli 1.5.0 → 1.6.0

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/_exports/build.d.ts +36 -1
  2. package/dist/_exports/build.js +1 -0
  3. package/dist/_exports/build.js.map +1 -1
  4. package/dist/_exports/deploy.d.ts +5 -1
  5. package/dist/_exports/index.d.ts +1 -1
  6. package/dist/_exports/preview.d.ts +169 -0
  7. package/dist/_exports/preview.js +3 -0
  8. package/dist/_exports/preview.js.map +1 -0
  9. package/dist/_exports/undeploy.d.ts +3 -1
  10. package/dist/actions/build/vite/optimize-deps.js +84 -0
  11. package/dist/actions/build/vite/optimize-deps.js.map +1 -0
  12. package/dist/actions/deploy/checkBuiltOutput.js +16 -2
  13. package/dist/actions/deploy/checkBuiltOutput.js.map +1 -1
  14. package/dist/actions/deploy/deployWorkbenchApp.js +17 -3
  15. package/dist/actions/deploy/deployWorkbenchApp.js.map +1 -1
  16. package/dist/actions/dev/registry.js +69 -1
  17. package/dist/actions/dev/registry.js.map +1 -1
  18. package/dist/actions/dev/startWorkbenchDev.js +6 -41
  19. package/dist/actions/dev/startWorkbenchDev.js.map +1 -1
  20. package/dist/actions/dev/startWorkbenchDevServer.js +7 -3
  21. package/dist/actions/dev/startWorkbenchDevServer.js.map +1 -1
  22. package/dist/actions/preview/serveBuiltApplication.js +53 -0
  23. package/dist/actions/preview/serveBuiltApplication.js.map +1 -0
  24. package/dist/actions/preview/startWorkbenchPreview.js +91 -0
  25. package/dist/actions/preview/startWorkbenchPreview.js.map +1 -0
  26. package/dist/defineApp.js +2 -5
  27. package/dist/defineApp.js.map +1 -1
  28. package/dist/resolveWorkbenchApp.js +1 -0
  29. package/dist/resolveWorkbenchApp.js.map +1 -1
  30. package/dist/services/applications.js +14 -1
  31. package/dist/services/applications.js.map +1 -1
  32. package/dist/util/serverOrchestration.js +75 -0
  33. package/dist/util/serverOrchestration.js.map +1 -0
  34. package/package.json +7 -3
@@ -87,7 +87,7 @@ declare const DefineAppInputSchema: z.ZodMiniObject<
87
87
  >
88
88
  >
89
89
  >;
90
- slug: z.ZodMiniOptional<z.ZodMiniString<string>>;
90
+ slug: z.ZodMiniString<string>;
91
91
  title: z.ZodMiniString<string>;
92
92
  views: z.ZodMiniOptional<
93
93
  z.ZodMiniArray<
@@ -141,6 +141,8 @@ declare interface ResolvedWorkbenchApp {
141
141
  readonly config?: WorkbenchApp["config"];
142
142
  /** SDK app-view entrypoint, when declared. */
143
143
  readonly entry?: string;
144
+ /** Path to the app's icon SVG, resolved and shipped to Brett on deploy. */
145
+ readonly icon?: string;
144
146
  /** Explicit singleton flag (a Sanity-owned app); `undefined` when the app doesn't set it. */
145
147
  readonly isSingleton?: boolean;
146
148
  /** Hostname the application is created at on first deploy. */
@@ -185,6 +187,39 @@ export declare interface WorkbenchExposes {
185
187
  views?: DefineAppInput["views"];
186
188
  }
187
189
 
190
+ /**
191
+ * Dep pre-bundling inputs for a workbench app's dev server.
192
+ *
193
+ * Vite's dep scanner crawls from the app's HTML entry, which reaches only the
194
+ * app's `entry` (or a studio's config) — never the federation `exposes` (dock
195
+ * views, worker services, media-library config fields), which the host loads
196
+ * dynamically at runtime. So a dep imported only by an exposed module (e.g.
197
+ * `sanity/workbench` in a service or view) escapes the startup scan; Vite
198
+ * discovers it on first request, re-optimizes, and full-page reloads — which
199
+ * flakes Playwright in e2e.
200
+ *
201
+ * Point `entries` at the source of every interface: the app `entry` (or, for a
202
+ * studio, its config), plus each view, service, and installation-config source.
203
+ * `entries` follows real import statements, so it covers whatever those sources
204
+ * transitively use — correct subpaths and all — with no hand-maintained dep
205
+ * list, and never crashes on an unresolvable name the way a bad `include` entry
206
+ * does. Each source is resolved to its on-disk file so an extensionless path
207
+ * (like the default `./src/App`) still matches `entries`' filesystem glob.
208
+ *
209
+ * @param cwd - Project root; `entries` are returned relative to it.
210
+ * @param appSources - Absolute paths to the app's `entry` and/or studio config.
211
+ * @param exposes - The app's declared views/services/config.
212
+ * @internal
213
+ */
214
+ export declare function workbenchOptimizeDeps(options: {
215
+ appSources: readonly string[];
216
+ cwd: string;
217
+ exposes?: WorkbenchExposes;
218
+ }): {
219
+ entries: string[];
220
+ include: string[];
221
+ };
222
+
188
223
  declare interface WorkbenchViteOptions {
189
224
  /** Project root — read for the federation remote name, and the plugin workDir. */
190
225
  cwd: string;
@@ -3,6 +3,7 @@
3
3
  // resolver the build reads declared views/services from. The build needs no
4
4
  // deploy-time guards, so it takes the bare `resolveWorkbenchApp` — the guarded
5
5
  // view (`getWorkbench`) is the deploy entry's export.
6
+ export { workbenchOptimizeDeps } from '../actions/build/vite/optimize-deps.js';
6
7
  export { workbenchVitePlugins } from '../actions/build/vite/workbench-vite-plugins.js';
7
8
  export { resolveWorkbenchApp } from '../resolveWorkbenchApp.js';
8
9
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/_exports/build.ts"],"sourcesContent":["// Node-only build entry: the module-federation Vite plugins that\n// `@sanity/cli-build`'s `getViteConfig` swaps in for a workbench app, plus the\n// resolver the build reads declared views/services from. The build needs no\n// deploy-time guards, so it takes the bare `resolveWorkbenchApp` — the guarded\n// view (`getWorkbench`) is the deploy entry's export.\n\nexport {workbenchVitePlugins} from '../actions/build/vite/workbench-vite-plugins.js'\nexport {resolveWorkbenchApp, type WorkbenchExposes} from '../resolveWorkbenchApp.js'\n"],"names":["workbenchVitePlugins","resolveWorkbenchApp"],"mappings":"AAAA,iEAAiE;AACjE,+EAA+E;AAC/E,4EAA4E;AAC5E,+EAA+E;AAC/E,sDAAsD;AAEtD,SAAQA,oBAAoB,QAAO,kDAAiD;AACpF,SAAQC,mBAAmB,QAA8B,4BAA2B"}
1
+ {"version":3,"sources":["../../src/_exports/build.ts"],"sourcesContent":["// Node-only build entry: the module-federation Vite plugins that\n// `@sanity/cli-build`'s `getViteConfig` swaps in for a workbench app, plus the\n// resolver the build reads declared views/services from. The build needs no\n// deploy-time guards, so it takes the bare `resolveWorkbenchApp` — the guarded\n// view (`getWorkbench`) is the deploy entry's export.\n\nexport {workbenchOptimizeDeps} from '../actions/build/vite/optimize-deps.js'\nexport {workbenchVitePlugins} from '../actions/build/vite/workbench-vite-plugins.js'\nexport {resolveWorkbenchApp, type WorkbenchExposes} from '../resolveWorkbenchApp.js'\n"],"names":["workbenchOptimizeDeps","workbenchVitePlugins","resolveWorkbenchApp"],"mappings":"AAAA,iEAAiE;AACjE,+EAA+E;AAC/E,4EAA4E;AAC5E,+EAA+E;AAC/E,sDAAsD;AAEtD,SAAQA,qBAAqB,QAAO,yCAAwC;AAC5E,SAAQC,oBAAoB,QAAO,kDAAiD;AACpF,SAAQC,mBAAmB,QAA8B,4BAA2B"}
@@ -177,7 +177,7 @@ declare const DefineAppInputSchema: z.ZodMiniObject<
177
177
  >
178
178
  >
179
179
  >;
180
- slug: z.ZodMiniOptional<z.ZodMiniString<string>>;
180
+ slug: z.ZodMiniString<string>;
181
181
  title: z.ZodMiniString<string>;
182
182
  views: z.ZodMiniOptional<
183
183
  z.ZodMiniArray<
@@ -261,6 +261,7 @@ export declare function deployConfig(options: {
261
261
  */
262
262
  export declare function deployCoreApp(options: {
263
263
  appId: string | undefined;
264
+ icon?: string;
264
265
  interfaces: readonly BrettInterface[];
265
266
  isAutoUpdating: boolean;
266
267
  isSingleton?: boolean;
@@ -290,6 +291,7 @@ export declare interface DeployedExpose {
290
291
  */
291
292
  export declare function deployStudio(options: {
292
293
  appId: string | undefined;
294
+ icon?: string;
293
295
  interfaces: readonly BrettInterface[];
294
296
  isAutoUpdating: boolean;
295
297
  organizationId: string;
@@ -333,6 +335,8 @@ declare interface ResolvedWorkbenchApp {
333
335
  readonly config?: WorkbenchApp["config"];
334
336
  /** SDK app-view entrypoint, when declared. */
335
337
  readonly entry?: string;
338
+ /** Path to the app's icon SVG, resolved and shipped to Brett on deploy. */
339
+ readonly icon?: string;
336
340
  /** Explicit singleton flag (a Sanity-owned app); `undefined` when the app doesn't set it. */
337
341
  readonly isSingleton?: boolean;
338
342
  /** Hostname the application is created at on first deploy. */
@@ -84,7 +84,7 @@ declare const DefineAppInputSchema: z.ZodMiniObject<
84
84
  >
85
85
  >
86
86
  >;
87
- slug: z.ZodMiniOptional<z.ZodMiniString<string>>;
87
+ slug: z.ZodMiniString<string>;
88
88
  title: z.ZodMiniString<string>;
89
89
  views: z.ZodMiniOptional<
90
90
  z.ZodMiniArray<
@@ -0,0 +1,169 @@
1
+ import { CliConfig } from "@sanity/cli-core";
2
+ import { Output } from "@sanity/cli-core";
3
+ import { z } from "zod/mini";
4
+
5
+ /**
6
+ * A manifest describing a running dev server process (studio or app).
7
+ * Stored as `~/.sanity/dev-servers/<pid>.json`.
8
+ *
9
+ * The workbench singleton is tracked separately via the lock file — see
10
+ * `acquireWorkbenchLock` and `readWorkbenchLock` below.
11
+ */
12
+ declare type DevServerManifest = z.infer<typeof devServerManifestSchema>;
13
+
14
+ declare const devServerManifestSchema: z.ZodMiniObject<
15
+ {
16
+ configs: z.ZodMiniOptional<
17
+ z.ZodMiniArray<
18
+ z.ZodMiniObject<
19
+ {
20
+ appType: z.ZodMiniOptional<z.ZodMiniString<string>>;
21
+ fields: z.ZodMiniArray<
22
+ z.ZodMiniObject<
23
+ {
24
+ name: z.ZodMiniString<string>;
25
+ public: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
26
+ src: z.ZodMiniString<string>;
27
+ title: z.ZodMiniString<string>;
28
+ },
29
+ z.core.$strip
30
+ >
31
+ >;
32
+ id: z.ZodMiniString<string>;
33
+ moduleName: z.ZodMiniOptional<z.ZodMiniString<string>>;
34
+ version: z.ZodMiniNumber<number>;
35
+ },
36
+ z.core.$strip
37
+ >
38
+ >
39
+ >;
40
+ host: z.ZodMiniString<string>;
41
+ id: z.ZodMiniOptional<z.ZodMiniString<string>>;
42
+ interfaces: z.ZodMiniOptional<
43
+ z.ZodMiniArray<
44
+ z.ZodMiniDiscriminatedUnion<
45
+ [
46
+ z.ZodMiniObject<
47
+ {
48
+ metadata: z.ZodMiniNullable<
49
+ z.ZodMiniObject<
50
+ {
51
+ group: z.ZodMiniOptional<z.ZodMiniString<string>>;
52
+ priority: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
53
+ },
54
+ z.core.$strip
55
+ >
56
+ >;
57
+ type: z.ZodMiniLiteral<"app">;
58
+ id: z.ZodMiniString<string>;
59
+ moduleId: z.ZodMiniString<string>;
60
+ name: z.ZodMiniString<string>;
61
+ src: z.ZodMiniString<string>;
62
+ title: z.ZodMiniString<string>;
63
+ version: z.ZodMiniOptional<z.ZodMiniString<string>>;
64
+ },
65
+ z.core.$strip
66
+ >,
67
+ z.ZodMiniObject<
68
+ {
69
+ metadata: z.ZodMiniNull;
70
+ type: z.ZodMiniLiteral<"panel">;
71
+ id: z.ZodMiniString<string>;
72
+ moduleId: z.ZodMiniString<string>;
73
+ name: z.ZodMiniString<string>;
74
+ src: z.ZodMiniString<string>;
75
+ title: z.ZodMiniString<string>;
76
+ version: z.ZodMiniOptional<z.ZodMiniString<string>>;
77
+ },
78
+ z.core.$strip
79
+ >,
80
+ z.ZodMiniObject<
81
+ {
82
+ metadata: z.ZodMiniNull;
83
+ type: z.ZodMiniLiteral<"worker">;
84
+ id: z.ZodMiniString<string>;
85
+ moduleId: z.ZodMiniString<string>;
86
+ name: z.ZodMiniString<string>;
87
+ src: z.ZodMiniString<string>;
88
+ title: z.ZodMiniString<string>;
89
+ version: z.ZodMiniOptional<z.ZodMiniString<string>>;
90
+ },
91
+ z.core.$strip
92
+ >,
93
+ ],
94
+ "type"
95
+ >
96
+ >
97
+ >;
98
+ manifest: z.ZodMiniOptional<
99
+ z.ZodMiniUnion<
100
+ readonly [
101
+ z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnknown>,
102
+ z.ZodMiniObject<
103
+ {
104
+ group: z.ZodMiniOptional<z.ZodMiniString<string>>;
105
+ icon: z.ZodMiniOptional<z.ZodMiniString<string>>;
106
+ priority: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
107
+ slug: z.ZodMiniOptional<z.ZodMiniString<string>>;
108
+ title: z.ZodMiniOptional<z.ZodMiniString<string>>;
109
+ version: z.ZodMiniString<string>;
110
+ },
111
+ z.core.$strip
112
+ >,
113
+ ]
114
+ >
115
+ >;
116
+ manifestUpdatedAt: z.ZodMiniOptional<z.ZodMiniString<string>>;
117
+ pid: z.ZodMiniNumber<number>;
118
+ port: z.ZodMiniNumber<number>;
119
+ projectId: z.ZodMiniOptional<z.ZodMiniString<string>>;
120
+ startedAt: z.ZodMiniString<string>;
121
+ type: z.ZodMiniEnum<{
122
+ coreApp: "coreApp";
123
+ studio: "studio";
124
+ }>;
125
+ version: z.ZodMiniLiteral<1>;
126
+ workDir: z.ZodMiniString<string>;
127
+ },
128
+ z.core.$strip
129
+ >;
130
+
131
+ /**
132
+ * `sanity start` for a workbench app: serve a production build the way dev serves
133
+ * a live one. The same singleton workbench shell renders it and the same registry
134
+ * advertises it — only the remote differs, static files from the build output
135
+ * instead of a live Vite dev server. There's no config watcher or rebuild: a
136
+ * build is fixed, so nothing re-syncs.
137
+ *
138
+ * A running workbench claims the configured port, so the built remote binds the
139
+ * next one. Without one the remote takes the configured port and announces its
140
+ * own URL.
141
+ */
142
+ export declare function startWorkbenchPreview(
143
+ options: StartWorkbenchPreviewOptions,
144
+ ): Promise<{
145
+ close: () => Promise<void>;
146
+ }>;
147
+
148
+ export declare interface StartWorkbenchPreviewOptions {
149
+ /** Directory for the workbench Vite server's dependency cache. */
150
+ cacheDir: string;
151
+ /** CLI-domain `app.id`/`deployment.appId` deprecation check, run before registering. */
152
+ checkForDeprecatedAppId: () => void;
153
+ cliConfig: CliConfig;
154
+ /** Extract the project manifest to inline into the registry (studio-vs-app handled by the CLI). */
155
+ extractManifest: (params: {
156
+ configPath: string;
157
+ workDir: string;
158
+ }) => Promise<DevServerManifest["manifest"]>;
159
+ httpHost: string;
160
+ httpPort: number;
161
+ isApp: boolean;
162
+ /** The built `dist` directory to serve as the federation remote. */
163
+ outDir: string;
164
+ output: Output;
165
+ reactStrictMode: boolean;
166
+ workDir: string;
167
+ }
168
+
169
+ export {};
@@ -0,0 +1,3 @@
1
+ export { startWorkbenchPreview } from '../actions/preview/startWorkbenchPreview.js';
2
+
3
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/_exports/preview.ts"],"sourcesContent":["export {\n startWorkbenchPreview,\n type StartWorkbenchPreviewOptions,\n} from '../actions/preview/startWorkbenchPreview.js'\n"],"names":["startWorkbenchPreview"],"mappings":"AAAA,SACEA,qBAAqB,QAEhB,8CAA6C"}
@@ -102,7 +102,7 @@ declare const DefineAppInputSchema: z.ZodMiniObject<
102
102
  >
103
103
  >
104
104
  >;
105
- slug: z.ZodMiniOptional<z.ZodMiniString<string>>;
105
+ slug: z.ZodMiniString<string>;
106
106
  title: z.ZodMiniString<string>;
107
107
  views: z.ZodMiniOptional<
108
108
  z.ZodMiniArray<
@@ -185,6 +185,8 @@ declare interface ResolvedWorkbenchApp {
185
185
  readonly config?: WorkbenchApp["config"];
186
186
  /** SDK app-view entrypoint, when declared. */
187
187
  readonly entry?: string;
188
+ /** Path to the app's icon SVG, resolved and shipped to Brett on deploy. */
189
+ readonly icon?: string;
188
190
  /** Explicit singleton flag (a Sanity-owned app); `undefined` when the app doesn't set it. */
189
191
  readonly isSingleton?: boolean;
190
192
  /** Hostname the application is created at on first deploy. */
@@ -0,0 +1,84 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ /**
4
+ * React APIs only the generated render-contract modules import — the SPA
5
+ * bootstrap (`getEntryModule`) and every render artifact (`renderRemote`)
6
+ * `createRoot` from `react-dom/client` and `createElement` from `react`. No
7
+ * app/interface source imports `react-dom/client` itself, so scanning `entries`
8
+ * never surfaces it; every workbench app depends on react/react-dom, so both
9
+ * always resolve.
10
+ */ const RENDER_CONTRACT_DEPS = [
11
+ 'react',
12
+ 'react-dom/client'
13
+ ];
14
+ /** Extensions an import-style source path may omit, in resolution order. */ const SOURCE_EXTENSIONS = [
15
+ '.tsx',
16
+ '.ts',
17
+ '.jsx',
18
+ '.js',
19
+ '.mjs',
20
+ '.cjs'
21
+ ];
22
+ /**
23
+ * Resolve an import-style source path to the file on disk. The app `entry`
24
+ * defaults to the extensionless `./src/App` (and a user may omit the extension
25
+ * anywhere), which the runtime imports fine through Vite's resolver — but
26
+ * `optimizeDeps.entries` is matched against the filesystem, so an extensionless
27
+ * path never matches and its deps go unscanned. Try the path as-is, then the
28
+ * common source extensions; fall back to the input so an already-resolved path
29
+ * (or a genuinely missing one) passes through unchanged.
30
+ */ function resolveSourceFile(absPath) {
31
+ if (fs.existsSync(absPath) && fs.statSync(absPath).isFile()) return absPath;
32
+ for (const extension of SOURCE_EXTENSIONS){
33
+ if (fs.existsSync(`${absPath}${extension}`)) return `${absPath}${extension}`;
34
+ }
35
+ return absPath;
36
+ }
37
+ /**
38
+ * Dep pre-bundling inputs for a workbench app's dev server.
39
+ *
40
+ * Vite's dep scanner crawls from the app's HTML entry, which reaches only the
41
+ * app's `entry` (or a studio's config) — never the federation `exposes` (dock
42
+ * views, worker services, media-library config fields), which the host loads
43
+ * dynamically at runtime. So a dep imported only by an exposed module (e.g.
44
+ * `sanity/workbench` in a service or view) escapes the startup scan; Vite
45
+ * discovers it on first request, re-optimizes, and full-page reloads — which
46
+ * flakes Playwright in e2e.
47
+ *
48
+ * Point `entries` at the source of every interface: the app `entry` (or, for a
49
+ * studio, its config), plus each view, service, and installation-config source.
50
+ * `entries` follows real import statements, so it covers whatever those sources
51
+ * transitively use — correct subpaths and all — with no hand-maintained dep
52
+ * list, and never crashes on an unresolvable name the way a bad `include` entry
53
+ * does. Each source is resolved to its on-disk file so an extensionless path
54
+ * (like the default `./src/App`) still matches `entries`' filesystem glob.
55
+ *
56
+ * @param cwd - Project root; `entries` are returned relative to it.
57
+ * @param appSources - Absolute paths to the app's `entry` and/or studio config.
58
+ * @param exposes - The app's declared views/services/config.
59
+ * @internal
60
+ */ export function workbenchOptimizeDeps(options) {
61
+ const { appSources, cwd, exposes } = options;
62
+ const interfaceSources = [
63
+ ...(exposes?.views ?? []).map((view)=>view.src),
64
+ ...(exposes?.services ?? []).map((service)=>service.src),
65
+ ...(exposes?.config?.fields ?? []).map((field)=>field.src)
66
+ ].map((src)=>path.resolve(cwd, src));
67
+ const entries = [
68
+ ...appSources,
69
+ ...interfaceSources
70
+ ].map((absPath)=>{
71
+ const resolved = resolveSourceFile(absPath);
72
+ return path.relative(cwd, resolved).split(path.sep).join('/');
73
+ });
74
+ return {
75
+ entries: [
76
+ ...new Set(entries)
77
+ ],
78
+ include: [
79
+ ...RENDER_CONTRACT_DEPS
80
+ ]
81
+ };
82
+ }
83
+
84
+ //# sourceMappingURL=optimize-deps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/actions/build/vite/optimize-deps.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\nimport {type WorkbenchExposes} from '../../../resolveWorkbenchApp.js'\n\n/**\n * React APIs only the generated render-contract modules import — the SPA\n * bootstrap (`getEntryModule`) and every render artifact (`renderRemote`)\n * `createRoot` from `react-dom/client` and `createElement` from `react`. No\n * app/interface source imports `react-dom/client` itself, so scanning `entries`\n * never surfaces it; every workbench app depends on react/react-dom, so both\n * always resolve.\n */\nconst RENDER_CONTRACT_DEPS = ['react', 'react-dom/client']\n\n/** Extensions an import-style source path may omit, in resolution order. */\nconst SOURCE_EXTENSIONS = ['.tsx', '.ts', '.jsx', '.js', '.mjs', '.cjs']\n\n/**\n * Resolve an import-style source path to the file on disk. The app `entry`\n * defaults to the extensionless `./src/App` (and a user may omit the extension\n * anywhere), which the runtime imports fine through Vite's resolver — but\n * `optimizeDeps.entries` is matched against the filesystem, so an extensionless\n * path never matches and its deps go unscanned. Try the path as-is, then the\n * common source extensions; fall back to the input so an already-resolved path\n * (or a genuinely missing one) passes through unchanged.\n */\nfunction resolveSourceFile(absPath: string): string {\n if (fs.existsSync(absPath) && fs.statSync(absPath).isFile()) return absPath\n for (const extension of SOURCE_EXTENSIONS) {\n if (fs.existsSync(`${absPath}${extension}`)) return `${absPath}${extension}`\n }\n return absPath\n}\n\n/**\n * Dep pre-bundling inputs for a workbench app's dev server.\n *\n * Vite's dep scanner crawls from the app's HTML entry, which reaches only the\n * app's `entry` (or a studio's config) — never the federation `exposes` (dock\n * views, worker services, media-library config fields), which the host loads\n * dynamically at runtime. So a dep imported only by an exposed module (e.g.\n * `sanity/workbench` in a service or view) escapes the startup scan; Vite\n * discovers it on first request, re-optimizes, and full-page reloads — which\n * flakes Playwright in e2e.\n *\n * Point `entries` at the source of every interface: the app `entry` (or, for a\n * studio, its config), plus each view, service, and installation-config source.\n * `entries` follows real import statements, so it covers whatever those sources\n * transitively use — correct subpaths and all — with no hand-maintained dep\n * list, and never crashes on an unresolvable name the way a bad `include` entry\n * does. Each source is resolved to its on-disk file so an extensionless path\n * (like the default `./src/App`) still matches `entries`' filesystem glob.\n *\n * @param cwd - Project root; `entries` are returned relative to it.\n * @param appSources - Absolute paths to the app's `entry` and/or studio config.\n * @param exposes - The app's declared views/services/config.\n * @internal\n */\nexport function workbenchOptimizeDeps(options: {\n appSources: readonly string[]\n cwd: string\n exposes?: WorkbenchExposes\n}): {entries: string[]; include: string[]} {\n const {appSources, cwd, exposes} = options\n\n const interfaceSources = [\n ...(exposes?.views ?? []).map((view) => view.src),\n ...(exposes?.services ?? []).map((service) => service.src),\n ...(exposes?.config?.fields ?? []).map((field) => field.src),\n ].map((src) => path.resolve(cwd, src))\n\n const entries = [...appSources, ...interfaceSources].map((absPath) => {\n const resolved = resolveSourceFile(absPath)\n return path.relative(cwd, resolved).split(path.sep).join('/')\n })\n\n return {\n entries: [...new Set(entries)],\n include: [...RENDER_CONTRACT_DEPS],\n }\n}\n"],"names":["fs","path","RENDER_CONTRACT_DEPS","SOURCE_EXTENSIONS","resolveSourceFile","absPath","existsSync","statSync","isFile","extension","workbenchOptimizeDeps","options","appSources","cwd","exposes","interfaceSources","views","map","view","src","services","service","config","fields","field","resolve","entries","resolved","relative","split","sep","join","Set","include"],"mappings":"AAAA,OAAOA,QAAQ,UAAS;AACxB,OAAOC,UAAU,YAAW;AAI5B;;;;;;;CAOC,GACD,MAAMC,uBAAuB;IAAC;IAAS;CAAmB;AAE1D,0EAA0E,GAC1E,MAAMC,oBAAoB;IAAC;IAAQ;IAAO;IAAQ;IAAO;IAAQ;CAAO;AAExE;;;;;;;;CAQC,GACD,SAASC,kBAAkBC,OAAe;IACxC,IAAIL,GAAGM,UAAU,CAACD,YAAYL,GAAGO,QAAQ,CAACF,SAASG,MAAM,IAAI,OAAOH;IACpE,KAAK,MAAMI,aAAaN,kBAAmB;QACzC,IAAIH,GAAGM,UAAU,CAAC,GAAGD,UAAUI,WAAW,GAAG,OAAO,GAAGJ,UAAUI,WAAW;IAC9E;IACA,OAAOJ;AACT;AAEA;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GACD,OAAO,SAASK,sBAAsBC,OAIrC;IACC,MAAM,EAACC,UAAU,EAAEC,GAAG,EAAEC,OAAO,EAAC,GAAGH;IAEnC,MAAMI,mBAAmB;WACpB,AAACD,CAAAA,SAASE,SAAS,EAAE,AAAD,EAAGC,GAAG,CAAC,CAACC,OAASA,KAAKC,GAAG;WAC7C,AAACL,CAAAA,SAASM,YAAY,EAAE,AAAD,EAAGH,GAAG,CAAC,CAACI,UAAYA,QAAQF,GAAG;WACtD,AAACL,CAAAA,SAASQ,QAAQC,UAAU,EAAE,AAAD,EAAGN,GAAG,CAAC,CAACO,QAAUA,MAAML,GAAG;KAC5D,CAACF,GAAG,CAAC,CAACE,MAAQlB,KAAKwB,OAAO,CAACZ,KAAKM;IAEjC,MAAMO,UAAU;WAAId;WAAeG;KAAiB,CAACE,GAAG,CAAC,CAACZ;QACxD,MAAMsB,WAAWvB,kBAAkBC;QACnC,OAAOJ,KAAK2B,QAAQ,CAACf,KAAKc,UAAUE,KAAK,CAAC5B,KAAK6B,GAAG,EAAEC,IAAI,CAAC;IAC3D;IAEA,OAAO;QACLL,SAAS;eAAI,IAAIM,IAAIN;SAAS;QAC9BO,SAAS;eAAI/B;SAAqB;IACpC;AACF"}
@@ -1,5 +1,15 @@
1
1
  import { stat } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
+ /**
4
+ * A genuinely-missing-build error, named so callers can offer the "run sanity
5
+ * build" hint (the `preview` command keys off this name, matching how the studio
6
+ * path keys off a missing `index.html`). Only the missing cases get it — real
7
+ * I/O failures keep their own name so they surface as themselves.
8
+ */ function buildNotFound(message) {
9
+ const error = new Error(message);
10
+ error.name = 'BUILD_NOT_FOUND';
11
+ return error;
12
+ }
3
13
  /**
4
14
  * Throws unless `sourceDir` is a directory holding a federation build.
5
15
  * A workbench build always emits a module-federation remote, and may
@@ -13,13 +23,17 @@ import { join } from 'node:path';
13
23
  throw new Error(`"${sourceDir}" is not a directory`);
14
24
  }
15
25
  } catch (err) {
16
- throw err.code === 'ENOENT' ? new Error(`Directory "${sourceDir}" does not exist`) : err;
26
+ if (err.code === 'ENOENT') throw buildNotFound(`Directory "${sourceDir}" does not exist`);
27
+ throw err;
17
28
  }
18
29
  const manifestPath = join(sourceDir, 'mf-manifest.json');
19
30
  try {
20
31
  await stat(manifestPath);
21
32
  } catch (err) {
22
- throw err.code === 'ENOENT' ? new Error(`"${manifestPath}" does not exist. ` + 'The deploy directory must contain a federation build created with "sanity build".') : err;
33
+ if (err.code === 'ENOENT') {
34
+ throw buildNotFound(`"${manifestPath}" does not exist. ` + 'The deploy directory must contain a federation build created with "sanity build".');
35
+ }
36
+ throw err;
23
37
  }
24
38
  }
25
39
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/checkBuiltOutput.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {join} from 'node:path'\n\n/**\n * Throws unless `sourceDir` is a directory holding a federation build.\n * A workbench build always emits a module-federation remote, and may\n * additionally emit a standalone `index.html` SPA (workbench remotes). Either\n * way `mf-manifest.json` is the reliable marker that `sanity build` produced a\n * federation build, so that — not `index.html` — is what we check for.\n */\nexport async function checkBuiltOutput(sourceDir: string): Promise<void> {\n try {\n const stats = await stat(sourceDir)\n if (!stats.isDirectory()) {\n throw new Error(`\"${sourceDir}\" is not a directory`)\n }\n } catch (err) {\n throw err.code === 'ENOENT' ? new Error(`Directory \"${sourceDir}\" does not exist`) : err\n }\n\n const manifestPath = join(sourceDir, 'mf-manifest.json')\n try {\n await stat(manifestPath)\n } catch (err) {\n throw err.code === 'ENOENT'\n ? new Error(\n `\"${manifestPath}\" does not exist. ` +\n 'The deploy directory must contain a federation build created with \"sanity build\".',\n )\n : err\n }\n}\n"],"names":["stat","join","checkBuiltOutput","sourceDir","stats","isDirectory","Error","err","code","manifestPath"],"mappings":"AAAA,SAAQA,IAAI,QAAO,mBAAkB;AACrC,SAAQC,IAAI,QAAO,YAAW;AAE9B;;;;;;CAMC,GACD,OAAO,eAAeC,iBAAiBC,SAAiB;IACtD,IAAI;QACF,MAAMC,QAAQ,MAAMJ,KAAKG;QACzB,IAAI,CAACC,MAAMC,WAAW,IAAI;YACxB,MAAM,IAAIC,MAAM,CAAC,CAAC,EAAEH,UAAU,oBAAoB,CAAC;QACrD;IACF,EAAE,OAAOI,KAAK;QACZ,MAAMA,IAAIC,IAAI,KAAK,WAAW,IAAIF,MAAM,CAAC,WAAW,EAAEH,UAAU,gBAAgB,CAAC,IAAII;IACvF;IAEA,MAAME,eAAeR,KAAKE,WAAW;IACrC,IAAI;QACF,MAAMH,KAAKS;IACb,EAAE,OAAOF,KAAK;QACZ,MAAMA,IAAIC,IAAI,KAAK,WACf,IAAIF,MACF,CAAC,CAAC,EAAEG,aAAa,kBAAkB,CAAC,GAClC,uFAEJF;IACN;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/checkBuiltOutput.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {join} from 'node:path'\n\n/**\n * A genuinely-missing-build error, named so callers can offer the \"run sanity\n * build\" hint (the `preview` command keys off this name, matching how the studio\n * path keys off a missing `index.html`). Only the missing cases get it — real\n * I/O failures keep their own name so they surface as themselves.\n */\nfunction buildNotFound(message: string): Error {\n const error = new Error(message)\n error.name = 'BUILD_NOT_FOUND'\n return error\n}\n\n/**\n * Throws unless `sourceDir` is a directory holding a federation build.\n * A workbench build always emits a module-federation remote, and may\n * additionally emit a standalone `index.html` SPA (workbench remotes). Either\n * way `mf-manifest.json` is the reliable marker that `sanity build` produced a\n * federation build, so that — not `index.html` — is what we check for.\n */\nexport async function checkBuiltOutput(sourceDir: string): Promise<void> {\n try {\n const stats = await stat(sourceDir)\n if (!stats.isDirectory()) {\n throw new Error(`\"${sourceDir}\" is not a directory`)\n }\n } catch (err) {\n if (err.code === 'ENOENT') throw buildNotFound(`Directory \"${sourceDir}\" does not exist`)\n throw err\n }\n\n const manifestPath = join(sourceDir, 'mf-manifest.json')\n try {\n await stat(manifestPath)\n } catch (err) {\n if (err.code === 'ENOENT') {\n throw buildNotFound(\n `\"${manifestPath}\" does not exist. ` +\n 'The deploy directory must contain a federation build created with \"sanity build\".',\n )\n }\n throw err\n }\n}\n"],"names":["stat","join","buildNotFound","message","error","Error","name","checkBuiltOutput","sourceDir","stats","isDirectory","err","code","manifestPath"],"mappings":"AAAA,SAAQA,IAAI,QAAO,mBAAkB;AACrC,SAAQC,IAAI,QAAO,YAAW;AAE9B;;;;;CAKC,GACD,SAASC,cAAcC,OAAe;IACpC,MAAMC,QAAQ,IAAIC,MAAMF;IACxBC,MAAME,IAAI,GAAG;IACb,OAAOF;AACT;AAEA;;;;;;CAMC,GACD,OAAO,eAAeG,iBAAiBC,SAAiB;IACtD,IAAI;QACF,MAAMC,QAAQ,MAAMT,KAAKQ;QACzB,IAAI,CAACC,MAAMC,WAAW,IAAI;YACxB,MAAM,IAAIL,MAAM,CAAC,CAAC,EAAEG,UAAU,oBAAoB,CAAC;QACrD;IACF,EAAE,OAAOG,KAAK;QACZ,IAAIA,IAAIC,IAAI,KAAK,UAAU,MAAMV,cAAc,CAAC,WAAW,EAAEM,UAAU,gBAAgB,CAAC;QACxF,MAAMG;IACR;IAEA,MAAME,eAAeZ,KAAKO,WAAW;IACrC,IAAI;QACF,MAAMR,KAAKa;IACb,EAAE,OAAOF,KAAK;QACZ,IAAIA,IAAIC,IAAI,KAAK,UAAU;YACzB,MAAMV,cACJ,CAAC,CAAC,EAAEW,aAAa,kBAAkB,CAAC,GAClC;QAEN;QACA,MAAMF;IACR;AACF"}
@@ -3,14 +3,14 @@ import { createGzip } from 'node:zlib';
3
3
  import { exitCodes } from '@sanity/cli-core';
4
4
  import { spinner } from '@sanity/cli-core/ux';
5
5
  import { pack } from 'tar-fs';
6
- import { createApplication, createDeployment } from '../../services/applications.js';
6
+ import { createApplication, createDeployment, updateApplication } from '../../services/applications.js';
7
7
  /**
8
8
  * Deploy a workbench coreApp through Brett: redeploy when `appId` is set,
9
9
  * otherwise create the application at `slug`. Returns the application id for the
10
10
  * shell to report.
11
11
  * @internal
12
12
  */ export async function deployCoreApp(options) {
13
- const { appId, interfaces, isAutoUpdating, isSingleton, organizationId, slug, sourceDir, title, version, visibility } = options;
13
+ const { appId, icon, interfaces, isAutoUpdating, isSingleton, organizationId, slug, sourceDir, title, version, visibility } = options;
14
14
  const tarball = pack(dirname(sourceDir), {
15
15
  entries: [
16
16
  basename(sourceDir)
@@ -26,12 +26,19 @@ import { createApplication, createDeployment } from '../../services/applications
26
26
  tarball,
27
27
  version
28
28
  });
29
+ await updateApplication(appId, {
30
+ title,
31
+ ...icon ? {
32
+ icon
33
+ } : {}
34
+ });
29
35
  spin.succeed();
30
36
  return {
31
37
  applicationId: appId
32
38
  };
33
39
  }
34
40
  const { id } = await createApplication({
41
+ icon,
35
42
  interfaces,
36
43
  isSingleton,
37
44
  organizationId,
@@ -57,7 +64,7 @@ import { createApplication, createDeployment } from '../../services/applications
57
64
  * the shell to report; a missing `studioHost` on create is a usage error.
58
65
  * @internal
59
66
  */ export async function deployStudio(options) {
60
- const { appId, interfaces, isAutoUpdating, organizationId, output, projectId, sourceDir, studioHost, title, version, workspaces } = options;
67
+ const { appId, icon, interfaces, isAutoUpdating, organizationId, output, projectId, sourceDir, studioHost, title, version, workspaces } = options;
61
68
  const tarball = pack(dirname(sourceDir), {
62
69
  entries: [
63
70
  basename(sourceDir)
@@ -74,6 +81,12 @@ import { createApplication, createDeployment } from '../../services/applications
74
81
  version,
75
82
  workspaces
76
83
  });
84
+ await updateApplication(appId, {
85
+ title,
86
+ ...icon ? {
87
+ icon
88
+ } : {}
89
+ });
77
90
  spin.succeed();
78
91
  return {
79
92
  applicationId: appId
@@ -86,6 +99,7 @@ import { createApplication, createDeployment } from '../../services/applications
86
99
  });
87
100
  }
88
101
  const application = await createApplication({
102
+ icon,
89
103
  interfaces,
90
104
  organizationId,
91
105
  projectId,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployWorkbenchApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {createGzip} from 'node:zlib'\n\nimport {type AppVisibility, exitCodes, type Output} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {pack} from 'tar-fs'\n\nimport {\n type BrettInterface,\n type BrettWorkspace,\n createApplication,\n createDeployment,\n} from '../../services/applications.js'\n\n/**\n * Deploy a workbench coreApp through Brett: redeploy when `appId` is set,\n * otherwise create the application at `slug`. Returns the application id for the\n * shell to report.\n * @internal\n */\nexport async function deployCoreApp(options: {\n appId: string | undefined\n interfaces: readonly BrettInterface[]\n isAutoUpdating: boolean\n isSingleton?: boolean\n organizationId: string\n slug: string\n sourceDir: string\n title: string\n version: string\n visibility?: AppVisibility\n}): Promise<{applicationId: string}> {\n const {\n appId,\n interfaces,\n isAutoUpdating,\n isSingleton,\n organizationId,\n slug,\n sourceDir,\n title,\n version,\n visibility,\n } = options\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n if (appId) {\n await createDeployment({applicationId: appId, interfaces, isAutoUpdating, tarball, version})\n spin.succeed()\n return {applicationId: appId}\n }\n\n const {id} = await createApplication({\n interfaces,\n isSingleton,\n organizationId,\n slug,\n tarball,\n title,\n type: 'coreApp',\n version,\n visibility,\n })\n spin.succeed()\n return {applicationId: id}\n } catch (error) {\n spin.clear()\n throw error\n }\n}\n\n/**\n * Deploy a workbench studio through Brett: redeploy when `appId` is set,\n * otherwise create the studio at `studioHost`. Returns the application id for\n * the shell to report; a missing `studioHost` on create is a usage error.\n * @internal\n */\nexport async function deployStudio(options: {\n appId: string | undefined\n interfaces: readonly BrettInterface[]\n isAutoUpdating: boolean\n organizationId: string\n output: Output\n projectId: string | undefined\n sourceDir: string\n studioHost: string | undefined\n title: string\n version: string\n workspaces: readonly BrettWorkspace[]\n}): Promise<{applicationId: string}> {\n const {\n appId,\n interfaces,\n isAutoUpdating,\n organizationId,\n output,\n projectId,\n sourceDir,\n studioHost,\n title,\n version,\n workspaces,\n } = options\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner('Deploying to sanity.studio').start()\n try {\n if (appId) {\n await createDeployment({\n applicationId: appId,\n interfaces,\n isAutoUpdating,\n tarball,\n version,\n workspaces,\n })\n spin.succeed()\n return {applicationId: appId}\n }\n\n if (!studioHost) {\n spin.fail()\n return output.error(\n 'No studio hostname configured. Set `studioHost` in sanity.cli.ts to create a studio.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n const application = await createApplication({\n interfaces,\n organizationId,\n projectId,\n slug: studioHost,\n tarball,\n title,\n type: 'studio',\n version,\n workspaces,\n })\n spin.succeed()\n return {applicationId: application.id}\n } catch (error) {\n spin.fail()\n throw error\n }\n}\n"],"names":["basename","dirname","createGzip","exitCodes","spinner","pack","createApplication","createDeployment","deployCoreApp","options","appId","interfaces","isAutoUpdating","isSingleton","organizationId","slug","sourceDir","title","version","visibility","tarball","entries","pipe","spin","start","applicationId","succeed","id","type","error","clear","deployStudio","output","projectId","studioHost","workspaces","fail","exit","USAGE_ERROR","application"],"mappings":"AAAA,SAAQA,QAAQ,EAAEC,OAAO,QAAO,YAAW;AAC3C,SAAQC,UAAU,QAAO,YAAW;AAEpC,SAA4BC,SAAS,QAAoB,mBAAkB;AAC3E,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,IAAI,QAAO,SAAQ;AAE3B,SAGEC,iBAAiB,EACjBC,gBAAgB,QACX,iCAAgC;AAEvC;;;;;CAKC,GACD,OAAO,eAAeC,cAAcC,OAWnC;IACC,MAAM,EACJC,KAAK,EACLC,UAAU,EACVC,cAAc,EACdC,WAAW,EACXC,cAAc,EACdC,IAAI,EACJC,SAAS,EACTC,KAAK,EACLC,OAAO,EACPC,UAAU,EACX,GAAGV;IACJ,MAAMW,UAAUf,KAAKJ,QAAQe,YAAY;QAACK,SAAS;YAACrB,SAASgB;SAAW;IAAA,GAAGM,IAAI,CAACpB;IAEhF,MAAMqB,OAAOnB,QAAQ,gBAAgBoB,KAAK;IAC1C,IAAI;QACF,IAAId,OAAO;YACT,MAAMH,iBAAiB;gBAACkB,eAAef;gBAAOC;gBAAYC;gBAAgBQ;gBAASF;YAAO;YAC1FK,KAAKG,OAAO;YACZ,OAAO;gBAACD,eAAef;YAAK;QAC9B;QAEA,MAAM,EAACiB,EAAE,EAAC,GAAG,MAAMrB,kBAAkB;YACnCK;YACAE;YACAC;YACAC;YACAK;YACAH;YACAW,MAAM;YACNV;YACAC;QACF;QACAI,KAAKG,OAAO;QACZ,OAAO;YAACD,eAAeE;QAAE;IAC3B,EAAE,OAAOE,OAAO;QACdN,KAAKO,KAAK;QACV,MAAMD;IACR;AACF;AAEA;;;;;CAKC,GACD,OAAO,eAAeE,aAAatB,OAYlC;IACC,MAAM,EACJC,KAAK,EACLC,UAAU,EACVC,cAAc,EACdE,cAAc,EACdkB,MAAM,EACNC,SAAS,EACTjB,SAAS,EACTkB,UAAU,EACVjB,KAAK,EACLC,OAAO,EACPiB,UAAU,EACX,GAAG1B;IACJ,MAAMW,UAAUf,KAAKJ,QAAQe,YAAY;QAACK,SAAS;YAACrB,SAASgB;SAAW;IAAA,GAAGM,IAAI,CAACpB;IAEhF,MAAMqB,OAAOnB,QAAQ,8BAA8BoB,KAAK;IACxD,IAAI;QACF,IAAId,OAAO;YACT,MAAMH,iBAAiB;gBACrBkB,eAAef;gBACfC;gBACAC;gBACAQ;gBACAF;gBACAiB;YACF;YACAZ,KAAKG,OAAO;YACZ,OAAO;gBAACD,eAAef;YAAK;QAC9B;QAEA,IAAI,CAACwB,YAAY;YACfX,KAAKa,IAAI;YACT,OAAOJ,OAAOH,KAAK,CACjB,wFACA;gBAACQ,MAAMlC,UAAUmC,WAAW;YAAA;QAEhC;QAEA,MAAMC,cAAc,MAAMjC,kBAAkB;YAC1CK;YACAG;YACAmB;YACAlB,MAAMmB;YACNd;YACAH;YACAW,MAAM;YACNV;YACAiB;QACF;QACAZ,KAAKG,OAAO;QACZ,OAAO;YAACD,eAAec,YAAYZ,EAAE;QAAA;IACvC,EAAE,OAAOE,OAAO;QACdN,KAAKa,IAAI;QACT,MAAMP;IACR;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployWorkbenchApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {createGzip} from 'node:zlib'\n\nimport {type AppVisibility, exitCodes, type Output} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {pack} from 'tar-fs'\n\nimport {\n type BrettInterface,\n type BrettWorkspace,\n createApplication,\n createDeployment,\n updateApplication,\n} from '../../services/applications.js'\n\n/**\n * Deploy a workbench coreApp through Brett: redeploy when `appId` is set,\n * otherwise create the application at `slug`. Returns the application id for the\n * shell to report.\n * @internal\n */\nexport async function deployCoreApp(options: {\n appId: string | undefined\n icon?: string\n interfaces: readonly BrettInterface[]\n isAutoUpdating: boolean\n isSingleton?: boolean\n organizationId: string\n slug: string\n sourceDir: string\n title: string\n version: string\n visibility?: AppVisibility\n}): Promise<{applicationId: string}> {\n const {\n appId,\n icon,\n interfaces,\n isAutoUpdating,\n isSingleton,\n organizationId,\n slug,\n sourceDir,\n title,\n version,\n visibility,\n } = options\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n if (appId) {\n await createDeployment({applicationId: appId, interfaces, isAutoUpdating, tarball, version})\n await updateApplication(appId, {title, ...(icon ? {icon} : {})})\n spin.succeed()\n return {applicationId: appId}\n }\n\n const {id} = await createApplication({\n icon,\n interfaces,\n isSingleton,\n organizationId,\n slug,\n tarball,\n title,\n type: 'coreApp',\n version,\n visibility,\n })\n spin.succeed()\n return {applicationId: id}\n } catch (error) {\n spin.clear()\n throw error\n }\n}\n\n/**\n * Deploy a workbench studio through Brett: redeploy when `appId` is set,\n * otherwise create the studio at `studioHost`. Returns the application id for\n * the shell to report; a missing `studioHost` on create is a usage error.\n * @internal\n */\nexport async function deployStudio(options: {\n appId: string | undefined\n icon?: string\n interfaces: readonly BrettInterface[]\n isAutoUpdating: boolean\n organizationId: string\n output: Output\n projectId: string | undefined\n sourceDir: string\n studioHost: string | undefined\n title: string\n version: string\n workspaces: readonly BrettWorkspace[]\n}): Promise<{applicationId: string}> {\n const {\n appId,\n icon,\n interfaces,\n isAutoUpdating,\n organizationId,\n output,\n projectId,\n sourceDir,\n studioHost,\n title,\n version,\n workspaces,\n } = options\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner('Deploying to sanity.studio').start()\n try {\n if (appId) {\n await createDeployment({\n applicationId: appId,\n interfaces,\n isAutoUpdating,\n tarball,\n version,\n workspaces,\n })\n await updateApplication(appId, {title, ...(icon ? {icon} : {})})\n spin.succeed()\n return {applicationId: appId}\n }\n\n if (!studioHost) {\n spin.fail()\n return output.error(\n 'No studio hostname configured. Set `studioHost` in sanity.cli.ts to create a studio.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n const application = await createApplication({\n icon,\n interfaces,\n organizationId,\n projectId,\n slug: studioHost,\n tarball,\n title,\n type: 'studio',\n version,\n workspaces,\n })\n spin.succeed()\n return {applicationId: application.id}\n } catch (error) {\n spin.fail()\n throw error\n }\n}\n"],"names":["basename","dirname","createGzip","exitCodes","spinner","pack","createApplication","createDeployment","updateApplication","deployCoreApp","options","appId","icon","interfaces","isAutoUpdating","isSingleton","organizationId","slug","sourceDir","title","version","visibility","tarball","entries","pipe","spin","start","applicationId","succeed","id","type","error","clear","deployStudio","output","projectId","studioHost","workspaces","fail","exit","USAGE_ERROR","application"],"mappings":"AAAA,SAAQA,QAAQ,EAAEC,OAAO,QAAO,YAAW;AAC3C,SAAQC,UAAU,QAAO,YAAW;AAEpC,SAA4BC,SAAS,QAAoB,mBAAkB;AAC3E,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,IAAI,QAAO,SAAQ;AAE3B,SAGEC,iBAAiB,EACjBC,gBAAgB,EAChBC,iBAAiB,QACZ,iCAAgC;AAEvC;;;;;CAKC,GACD,OAAO,eAAeC,cAAcC,OAYnC;IACC,MAAM,EACJC,KAAK,EACLC,IAAI,EACJC,UAAU,EACVC,cAAc,EACdC,WAAW,EACXC,cAAc,EACdC,IAAI,EACJC,SAAS,EACTC,KAAK,EACLC,OAAO,EACPC,UAAU,EACX,GAAGX;IACJ,MAAMY,UAAUjB,KAAKJ,QAAQiB,YAAY;QAACK,SAAS;YAACvB,SAASkB;SAAW;IAAA,GAAGM,IAAI,CAACtB;IAEhF,MAAMuB,OAAOrB,QAAQ,gBAAgBsB,KAAK;IAC1C,IAAI;QACF,IAAIf,OAAO;YACT,MAAMJ,iBAAiB;gBAACoB,eAAehB;gBAAOE;gBAAYC;gBAAgBQ;gBAASF;YAAO;YAC1F,MAAMZ,kBAAkBG,OAAO;gBAACQ;gBAAO,GAAIP,OAAO;oBAACA;gBAAI,IAAI,CAAC,CAAC;YAAC;YAC9Da,KAAKG,OAAO;YACZ,OAAO;gBAACD,eAAehB;YAAK;QAC9B;QAEA,MAAM,EAACkB,EAAE,EAAC,GAAG,MAAMvB,kBAAkB;YACnCM;YACAC;YACAE;YACAC;YACAC;YACAK;YACAH;YACAW,MAAM;YACNV;YACAC;QACF;QACAI,KAAKG,OAAO;QACZ,OAAO;YAACD,eAAeE;QAAE;IAC3B,EAAE,OAAOE,OAAO;QACdN,KAAKO,KAAK;QACV,MAAMD;IACR;AACF;AAEA;;;;;CAKC,GACD,OAAO,eAAeE,aAAavB,OAalC;IACC,MAAM,EACJC,KAAK,EACLC,IAAI,EACJC,UAAU,EACVC,cAAc,EACdE,cAAc,EACdkB,MAAM,EACNC,SAAS,EACTjB,SAAS,EACTkB,UAAU,EACVjB,KAAK,EACLC,OAAO,EACPiB,UAAU,EACX,GAAG3B;IACJ,MAAMY,UAAUjB,KAAKJ,QAAQiB,YAAY;QAACK,SAAS;YAACvB,SAASkB;SAAW;IAAA,GAAGM,IAAI,CAACtB;IAEhF,MAAMuB,OAAOrB,QAAQ,8BAA8BsB,KAAK;IACxD,IAAI;QACF,IAAIf,OAAO;YACT,MAAMJ,iBAAiB;gBACrBoB,eAAehB;gBACfE;gBACAC;gBACAQ;gBACAF;gBACAiB;YACF;YACA,MAAM7B,kBAAkBG,OAAO;gBAACQ;gBAAO,GAAIP,OAAO;oBAACA;gBAAI,IAAI,CAAC,CAAC;YAAC;YAC9Da,KAAKG,OAAO;YACZ,OAAO;gBAACD,eAAehB;YAAK;QAC9B;QAEA,IAAI,CAACyB,YAAY;YACfX,KAAKa,IAAI;YACT,OAAOJ,OAAOH,KAAK,CACjB,wFACA;gBAACQ,MAAMpC,UAAUqC,WAAW;YAAA;QAEhC;QAEA,MAAMC,cAAc,MAAMnC,kBAAkB;YAC1CM;YACAC;YACAG;YACAmB;YACAlB,MAAMmB;YACNd;YACAH;YACAW,MAAM;YACNV;YACAiB;QACF;QACAZ,KAAKG,OAAO;QACZ,OAAO;YAACD,eAAec,YAAYZ,EAAE;QAAA;IACvC,EAAE,OAAOE,OAAO;QACdN,KAAKa,IAAI;QACT,MAAMP;IACR;AACF"}