@sanity/workbench-cli 2.2.2 → 2.2.4

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.
@@ -1,4 +1,4 @@
1
- import { a as resolveWorkbenchApp, i as WorkbenchExposes, n as resolveWorkbenchConfig, r as ResolvedWorkbenchApp, t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-6iznHbED.js";
1
+ import { a as resolveWorkbenchApp, i as WorkbenchExposes, n as resolveWorkbenchConfig, r as ResolvedWorkbenchApp, t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-0Crh5P9n.js";
2
2
  import { PluginOption } from "vite";
3
3
  /**
4
4
  * Dep pre-bundling inputs for a workbench app's dev server.
@@ -214,6 +214,7 @@ declare const DefineAppInputSchema: z.ZodMiniObject<{
214
214
  }, z.core.$strip>>;
215
215
  entry: z.ZodMiniOptional<z.ZodMiniString<string>>;
216
216
  icon: z.ZodMiniOptional<z.ZodMiniString<string>>;
217
+ isSingleton: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
217
218
  name: z.ZodMiniOptional<z.ZodMiniString<string>>;
218
219
  organizationId: z.ZodMiniString<string>;
219
220
  slug: z.ZodMiniString<string>;
@@ -275,10 +276,10 @@ declare const DefineAppInputSchema: z.ZodMiniObject<{
275
276
  }, z.core.$strip>;
276
277
  /**
277
278
  * User-facing input for `defineApplication`. Excludes the internal
278
- * `applicationType`.
279
+ * `applicationType` and `isSingleton`.
279
280
  * @public
280
281
  */
281
- type DefineAppInput = Omit<z.output<typeof DefineAppInputSchema>, 'applicationType'>;
282
+ type DefineAppInput = Omit<z.output<typeof DefineAppInputSchema>, 'applicationType' | 'isSingleton'>;
282
283
  /**
283
284
  * Nominal brand the CLI discriminates on to enable the workbench build/deploy
284
285
  * codepath. Registered via `Symbol.for` so the marker survives module-realm
@@ -372,4 +373,4 @@ declare function isWorkbenchConfig(app: unknown): app is WorkbenchConfig;
372
373
  */
373
374
  declare function unstable_defineMediaLibrary(input: DefineMediaLibraryInput): WorkbenchConfig;
374
375
  export { WorkbenchConfigValue as A, VIEW_CONTRACT_VERSION as C, ViewSurface as D, ViewDeclaration as E, defineWindowView as F, definePanelView as M, defineTileView as N, WebWorker as O, defineWebWorker as P, TileView as S, ViewComponentBaseProps as T, DockGroup as _, WorkbenchApp as a, ServiceType as b, isWorkbenchApp as c, AssetSourceView as d, DefineAssetSourceViewInput as f, DefineWindowViewInput as g, DefineWebWorkerInput as h, MediaLibraryField as i, defineAssetSourceView as j, WindowView as k, isWorkbenchConfig as l, DefineTileViewInput as m, DefineAppResult as n, WorkbenchConfig as o, DefinePanelViewInput as p, DefineMediaLibraryInput as r, defineApplication as s, DefineAppInput as t, unstable_defineMediaLibrary as u, PanelView as v, ViewComponent as w, TileSize as x, SERVICE_CONTRACT_VERSION as y };
375
- //# sourceMappingURL=defineApp-DldjQwq6.d.ts.map
376
+ //# sourceMappingURL=defineApp-Dmrf4GjS.d.ts.map
@@ -1,6 +1,6 @@
1
- import "./defineApp-DldjQwq6.js";
2
- import { n as resolveWorkbenchConfig, t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-6iznHbED.js";
3
- import { a as DeployableWorkbenchApp, i as summarizeInterfaces, n as DeployedView, o as getWorkbench, r as DeployedWebWorker, t as DeployedInterface } from "./summarizeInterfaces-CjkeWwkY.js";
1
+ import "./defineApp-Dmrf4GjS.js";
2
+ import { n as resolveWorkbenchConfig, t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-0Crh5P9n.js";
3
+ import { a as DeployableWorkbenchApp, i as summarizeInterfaces, n as DeployedView, o as getWorkbench, r as DeployedWebWorker, t as DeployedInterface } from "./summarizeInterfaces-CaYUOK3F.js";
4
4
  import { AppVisibility, CliConfig, Output } from "@sanity/cli-core";
5
5
  import "node:zlib";
6
6
  /**
@@ -117,6 +117,7 @@ interface CreatedApplication {
117
117
  * @internal
118
118
  */
119
119
  declare function createCoreApp(options: {
120
+ isSingleton?: boolean;
120
121
  name?: string;
121
122
  organizationId: string;
122
123
  slug: string;
@@ -22,6 +22,7 @@ interface StartWorkbenchDevOptions {
22
22
  cliConfig: CliConfig;
23
23
  /** Extract the project manifest to inline into the registry (studio-vs-app handled by the CLI). */
24
24
  extractManifest: (params: {
25
+ applicationId?: string;
25
26
  configPath: string;
26
27
  workDir: string;
27
28
  }) => Promise<DevServerManifest['manifest']>;
@@ -1,4 +1,4 @@
1
- import { C as VIEW_CONTRACT_VERSION, D as ViewSurface, E as ViewDeclaration, F as defineWindowView, M as definePanelView, N as defineTileView, O as WebWorker, P as defineWebWorker, S as TileView, T as ViewComponentBaseProps, _ as DockGroup, a as WorkbenchApp, b as ServiceType, c as isWorkbenchApp, d as AssetSourceView, f as DefineAssetSourceViewInput, g as DefineWindowViewInput, h as DefineWebWorkerInput, i as MediaLibraryField, j as defineAssetSourceView, k as WindowView, l as isWorkbenchConfig, m as DefineTileViewInput, n as DefineAppResult, o as WorkbenchConfig, p as DefinePanelViewInput, r as DefineMediaLibraryInput, s as defineApplication, t as DefineAppInput, u as unstable_defineMediaLibrary, v as PanelView, w as ViewComponent, x as TileSize, y as SERVICE_CONTRACT_VERSION } from "./defineApp-DldjQwq6.js";
1
+ import { C as VIEW_CONTRACT_VERSION, D as ViewSurface, E as ViewDeclaration, F as defineWindowView, M as definePanelView, N as defineTileView, O as WebWorker, P as defineWebWorker, S as TileView, T as ViewComponentBaseProps, _ as DockGroup, a as WorkbenchApp, b as ServiceType, c as isWorkbenchApp, d as AssetSourceView, f as DefineAssetSourceViewInput, g as DefineWindowViewInput, h as DefineWebWorkerInput, i as MediaLibraryField, j as defineAssetSourceView, k as WindowView, l as isWorkbenchConfig, m as DefineTileViewInput, n as DefineAppResult, o as WorkbenchConfig, p as DefinePanelViewInput, r as DefineMediaLibraryInput, s as defineApplication, t as DefineAppInput, u as unstable_defineMediaLibrary, v as PanelView, w as ViewComponent, x as TileSize, y as SERVICE_CONTRACT_VERSION } from "./defineApp-Dmrf4GjS.js";
2
2
  import { AssetSourceComponentProps } from "@sanity/types";
3
3
  /**
4
4
  * The service's own declaration, surfaced to the callback.
@@ -8,6 +8,7 @@ interface StartWorkbenchPreviewOptions {
8
8
  cliConfig: CliConfig;
9
9
  /** Extract the project manifest to inline into the registry (studio-vs-app handled by the CLI). */
10
10
  extractManifest: (params: {
11
+ applicationId?: string;
11
12
  configPath: string;
12
13
  workDir: string;
13
14
  }) => Promise<DevServerManifest['manifest']>;
@@ -1,4 +1,4 @@
1
- import { A as WorkbenchConfigValue, t as DefineAppInput } from "./defineApp-DldjQwq6.js";
1
+ import { A as WorkbenchConfigValue, t as DefineAppInput } from "./defineApp-Dmrf4GjS.js";
2
2
  import { AppVisibility, CliConfig } from "@sanity/cli-core";
3
3
  /**
4
4
  * Bundled so adding a declaration family touches this type and the artifact
@@ -31,6 +31,8 @@ interface ResolvedWorkbenchApp {
31
31
  readonly entry?: string;
32
32
  /** Path to the app's icon SVG, resolved and shipped to Brett on deploy. */
33
33
  readonly icon?: string;
34
+ /** Explicit singleton flag for Sanity-owned apps. */
35
+ readonly isSingleton?: boolean;
34
36
  /** Dashboard visibility declared by the app; `undefined` when unset. */
35
37
  readonly visibility?: AppVisibility;
36
38
  }
@@ -57,4 +59,4 @@ interface ResolvedMediaLibraryConfig {
57
59
  */
58
60
  declare function resolveWorkbenchConfig(cliConfig: CliConfig | null | undefined): ResolvedMediaLibraryConfig | null;
59
61
  export { resolveWorkbenchApp as a, WorkbenchExposes as i, resolveWorkbenchConfig as n, ResolvedWorkbenchApp as r, ResolvedMediaLibraryConfig as t };
60
- //# sourceMappingURL=resolveWorkbenchConfig-6iznHbED.d.ts.map
62
+ //# sourceMappingURL=resolveWorkbenchConfig-0Crh5P9n.d.ts.map
@@ -1,5 +1,5 @@
1
- import { D as ViewSurface, b as ServiceType } from "./defineApp-DldjQwq6.js";
2
- import { i as WorkbenchExposes, r as ResolvedWorkbenchApp } from "./resolveWorkbenchConfig-6iznHbED.js";
1
+ import { D as ViewSurface, b as ServiceType } from "./defineApp-Dmrf4GjS.js";
2
+ import { i as WorkbenchExposes, r as ResolvedWorkbenchApp } from "./resolveWorkbenchConfig-0Crh5P9n.js";
3
3
  import { CliConfig } from "@sanity/cli-core";
4
4
  import { z } from "zod/mini";
5
5
  /**
@@ -62,4 +62,4 @@ declare function summarizeInterfaces({ views, webWorkers }: WorkbenchExposes): {
62
62
  views: DeployedView[];
63
63
  };
64
64
  export { DeployableWorkbenchApp as a, summarizeInterfaces as i, DeployedView as n, getWorkbench as o, DeployedWebWorker as r, DeployedInterface as t };
65
- //# sourceMappingURL=summarizeInterfaces-CjkeWwkY.d.ts.map
65
+ //# sourceMappingURL=summarizeInterfaces-CaYUOK3F.d.ts.map
@@ -1,5 +1,5 @@
1
- import { t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-6iznHbED.js";
2
- import { a as DeployableWorkbenchApp, n as DeployedView, r as DeployedWebWorker } from "./summarizeInterfaces-CjkeWwkY.js";
1
+ import { t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-0Crh5P9n.js";
2
+ import { a as DeployableWorkbenchApp, n as DeployedView, r as DeployedWebWorker } from "./summarizeInterfaces-CaYUOK3F.js";
3
3
  import "node:zlib";
4
4
  import { UndeployAdapter, UndeployApplicationTarget, UndeployConfigTarget } from "@sanity/cli-core/undeploy";
5
5
  interface ConfigSnapshot {
@@ -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, type CliConfig} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {pack} from 'tar-fs'\n\nimport {type DerivedInterface, deriveInterfaces} from '../../deriveInterfaces.js'\nimport {\n type Application,\n type BrettAccess,\n type BrettInterface,\n type BrettWorkspace,\n createApplication,\n createDeployment,\n deleteApplication,\n updateApplication,\n} from '../../services/applications.js'\n\n/**\n * `rollback` undoes the creation, so a later failure leaves no record stranded at the slug.\n * @internal\n */\nexport interface CreatedApplication {\n application: Application\n rollback: () => Promise<void>\n}\n\nfunction toBrettInterface(iface: DerivedInterface, version: string): BrettInterface {\n const {id: _id, src: _src, ...declaration} = iface\n if ('type' in declaration) return {...declaration, version}\n\n switch (declaration.surface) {\n case 'app': {\n const {surface, ...view} = declaration\n return {...view, type: surface, version}\n }\n case 'asset_source': {\n const {surface, ...view} = declaration\n return {...view, type: surface, version}\n }\n case 'panel': {\n const {surface, ...view} = declaration\n return {...view, type: surface, version}\n }\n case 'tile': {\n const {surface, ...view} = declaration\n return {...view, type: surface, version}\n }\n }\n}\n\n/**\n * Create a coreApp record (no deployment), so the CLI can build with its id\n * before shipping the first deployment. First deploy only.\n * @internal\n */\nexport async function createCoreApp(options: {\n name?: string\n organizationId: string\n slug: string\n title: string\n visibility?: AppVisibility\n}): Promise<CreatedApplication> {\n const spin = spinner('Creating application...').start()\n try {\n const application = await createApplication({...options, type: 'coreApp'})\n spin.succeed()\n return {application, rollback: () => deleteApplication(application.id)}\n } catch (error) {\n spin.fail()\n throw error\n }\n}\n\n/**\n * Create a studio record (no deployment).\n * @internal\n */\nexport async function createStudio(options: {\n name?: string\n organizationId: string\n projectId: string | undefined\n slug: string\n title: string\n visibility?: AppVisibility\n}): Promise<CreatedApplication> {\n const spin = spinner('Creating studio...').start()\n try {\n const application = await createApplication({...options, type: 'studio'})\n spin.succeed()\n return {application, rollback: () => deleteApplication(application.id)}\n } catch (error) {\n spin.fail()\n throw error\n }\n}\n\n/**\n * Ship a deployment to an already-created (or `deployment.appId`) application,\n * then sync its mutable metadata (`title`, and `icon`/`visibility` when set)\n * from config. The deploy endpoint ignores these, so a redeploy patches them\n * here alongside the new deployment.\n *\n * `onDeployed` fires the instant the deployment is live, before the metadata\n * sync — so a caller can disarm a create-time rollback that must not delete an\n * application once it has an active deployment.\n * @internal\n */\nexport async function deployWorkbenchApp(options: {\n access?: readonly BrettAccess[]\n app: CliConfig['app']\n applicationId: string\n icon?: string\n isApp: boolean\n isAutoUpdating: boolean\n label?: string\n onDeployed?: () => void\n sourceDir: string\n title: string\n version: string\n visibility?: AppVisibility\n workspaces?: readonly BrettWorkspace[]\n}): Promise<void> {\n const {\n access,\n app,\n applicationId,\n icon,\n isApp,\n isAutoUpdating,\n label = 'Deploying...',\n onDeployed,\n sourceDir,\n title,\n version,\n visibility,\n workspaces,\n } = options\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner(label).start()\n try {\n await createDeployment({\n access,\n applicationId,\n // Brett assigns the id and resolves modules by `moduleId`, so neither travels.\n interfaces: deriveInterfaces(app, {appTitle: title, isApp}).map((iface) =>\n toBrettInterface(iface, version),\n ),\n isAutoUpdating,\n tarball,\n version,\n workspaces,\n })\n onDeployed?.()\n await updateApplication(applicationId, {\n title,\n ...(icon ? {icon} : {}),\n ...(visibility ? {visibility} : {}),\n })\n spin.succeed()\n } catch (error) {\n spin.clear()\n throw error\n }\n}\n"],"names":["basename","dirname","createGzip","spinner","pack","deriveInterfaces","createApplication","createDeployment","deleteApplication","updateApplication","toBrettInterface","iface","version","id","_id","src","_src","declaration","surface","view","type","createCoreApp","options","spin","start","application","succeed","rollback","error","fail","createStudio","deployWorkbenchApp","access","app","applicationId","icon","isApp","isAutoUpdating","label","onDeployed","sourceDir","title","visibility","workspaces","tarball","entries","pipe","interfaces","appTitle","map","clear"],"mappings":"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"}
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, type CliConfig} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {pack} from 'tar-fs'\n\nimport {type DerivedInterface, deriveInterfaces} from '../../deriveInterfaces.js'\nimport {\n type Application,\n type BrettAccess,\n type BrettInterface,\n type BrettWorkspace,\n createApplication,\n createDeployment,\n deleteApplication,\n updateApplication,\n} from '../../services/applications.js'\n\n/**\n * `rollback` undoes the creation, so a later failure leaves no record stranded at the slug.\n * @internal\n */\nexport interface CreatedApplication {\n application: Application\n rollback: () => Promise<void>\n}\n\nfunction toBrettInterface(iface: DerivedInterface, version: string): BrettInterface {\n const {id: _id, src: _src, ...declaration} = iface\n if ('type' in declaration) return {...declaration, version}\n\n switch (declaration.surface) {\n case 'app': {\n const {surface, ...view} = declaration\n return {...view, type: surface, version}\n }\n case 'asset_source': {\n const {surface, ...view} = declaration\n return {...view, type: surface, version}\n }\n case 'panel': {\n const {surface, ...view} = declaration\n return {...view, type: surface, version}\n }\n case 'tile': {\n const {surface, ...view} = declaration\n return {...view, type: surface, version}\n }\n }\n}\n\n/**\n * Create a coreApp record (no deployment), so the CLI can build with its id\n * before shipping the first deployment. First deploy only.\n * @internal\n */\nexport async function createCoreApp(options: {\n isSingleton?: boolean\n name?: string\n organizationId: string\n slug: string\n title: string\n visibility?: AppVisibility\n}): Promise<CreatedApplication> {\n const spin = spinner('Creating application...').start()\n try {\n const application = await createApplication({...options, type: 'coreApp'})\n spin.succeed()\n return {application, rollback: () => deleteApplication(application.id)}\n } catch (error) {\n spin.fail()\n throw error\n }\n}\n\n/**\n * Create a studio record (no deployment).\n * @internal\n */\nexport async function createStudio(options: {\n name?: string\n organizationId: string\n projectId: string | undefined\n slug: string\n title: string\n visibility?: AppVisibility\n}): Promise<CreatedApplication> {\n const spin = spinner('Creating studio...').start()\n try {\n const application = await createApplication({...options, type: 'studio'})\n spin.succeed()\n return {application, rollback: () => deleteApplication(application.id)}\n } catch (error) {\n spin.fail()\n throw error\n }\n}\n\n/**\n * Ship a deployment to an already-created (or `deployment.appId`) application,\n * then sync its mutable metadata (`title`, and `icon`/`visibility` when set)\n * from config. The deploy endpoint ignores these, so a redeploy patches them\n * here alongside the new deployment.\n *\n * `onDeployed` fires the instant the deployment is live, before the metadata\n * sync — so a caller can disarm a create-time rollback that must not delete an\n * application once it has an active deployment.\n * @internal\n */\nexport async function deployWorkbenchApp(options: {\n access?: readonly BrettAccess[]\n app: CliConfig['app']\n applicationId: string\n icon?: string\n isApp: boolean\n isAutoUpdating: boolean\n label?: string\n onDeployed?: () => void\n sourceDir: string\n title: string\n version: string\n visibility?: AppVisibility\n workspaces?: readonly BrettWorkspace[]\n}): Promise<void> {\n const {\n access,\n app,\n applicationId,\n icon,\n isApp,\n isAutoUpdating,\n label = 'Deploying...',\n onDeployed,\n sourceDir,\n title,\n version,\n visibility,\n workspaces,\n } = options\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner(label).start()\n try {\n await createDeployment({\n access,\n applicationId,\n // Brett assigns the id and resolves modules by `moduleId`, so neither travels.\n interfaces: deriveInterfaces(app, {appTitle: title, isApp}).map((iface) =>\n toBrettInterface(iface, version),\n ),\n isAutoUpdating,\n tarball,\n version,\n workspaces,\n })\n onDeployed?.()\n await updateApplication(applicationId, {\n title,\n ...(icon ? {icon} : {}),\n ...(visibility ? {visibility} : {}),\n })\n spin.succeed()\n } catch (error) {\n spin.clear()\n throw error\n }\n}\n"],"names":["basename","dirname","createGzip","spinner","pack","deriveInterfaces","createApplication","createDeployment","deleteApplication","updateApplication","toBrettInterface","iface","version","id","_id","src","_src","declaration","surface","view","type","createCoreApp","options","spin","start","application","succeed","rollback","error","fail","createStudio","deployWorkbenchApp","access","app","applicationId","icon","isApp","isAutoUpdating","label","onDeployed","sourceDir","title","visibility","workspaces","tarball","entries","pipe","interfaces","appTitle","map","clear"],"mappings":"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"}
@@ -94,7 +94,10 @@ import { startDevManifestWatcher } from './startDevManifestWatcher.js';
94
94
  interfaces: deriveInterfaces(nextConfig.app, {
95
95
  isApp
96
96
  }),
97
- manifest: await extractManifest(params)
97
+ manifest: await extractManifest({
98
+ ...params,
99
+ applicationId: id
100
+ })
98
101
  };
99
102
  },
100
103
  // A studio's root resolves to `sanity.config.*` but its interfaces live in
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/dev/startDevServerRegistration.ts"],"sourcesContent":["import {type CliConfig, getCliConfigUncached, type Output} from '@sanity/cli-core'\nimport {type ViteDevServer} from 'vite'\n\nimport {applicationReference} from '../../applicationReference.js'\nimport {isWorkbenchApp, isWorkbenchConfig} from '../../defineApp.js'\nimport {deriveInterfaces} from '../../deriveInterfaces.js'\nimport {resolveWorkbenchConfig} from '../../resolveWorkbenchConfig.js'\nimport {formatWorkbenchAppErrors, validateWorkbenchApp} from '../../validateWorkbenchApp.js'\nimport {deriveConfigs} from './deriveConfigs.js'\nimport {trackExposesSet} from './exposesSetId.js'\nimport {type DevServerManifest, getRegisteredServers, registerDevServer} from './registry.js'\nimport {startDevManifestWatcher} from './startDevManifestWatcher.js'\n\ninterface DevServerRegistrationOptions {\n cliConfig: CliConfig\n /**\n * Extract the project manifest to inline into the registry. The caller owns the\n * studio-vs-app split (manifest formats are CLI-domain); registration re-derives\n * the interface set alongside it.\n */\n extractManifest: (params: {\n configPath: string\n workDir: string\n }) => Promise<DevServerManifest['manifest']>\n isApp: boolean\n output: Output\n server: ViteDevServer\n workDir: string\n\n /**\n * Rebuild the app's federation remote when its interface set changes, awaited\n * *before* the registry patch — the patch reloads the workbench page, which must\n * re-fetch a remote that already exposes the new interface. Resolves with the\n * recreated server so the entry gets its actual address (non-strict ports may\n * shift it); must reject if the restart produces no server, so the set stays\n * uncommitted and the next save retries instead of advertising a dead port.\n */\n onInterfaceSetChange?: () => Promise<ViteDevServer>\n}\n\ninterface DevServerRegistrationHandle {\n close: () => Promise<void>\n}\n\n/**\n * Log any app validation errors without aborting. Unlike build and deploy, dev\n * stays up on an invalid app so the author sees the errors and fixes them live on\n * the next save. A config is not an app — it isn't validated by the app schema\n * (which would spuriously demand a slug/title), so skip it here.\n */\nfunction reportConfigErrors(app: CliConfig['app'], output: Output): void {\n if (isWorkbenchConfig(app)) return\n const errors = validateWorkbenchApp(app)\n if (errors.length === 0) return\n output.warn(formatWorkbenchAppErrors(errors))\n}\n\n/** The address the server actually bound — the live socket, which can differ from the configured port under non-strict ports. */\nfunction serverAddress(server: ViteDevServer) {\n const resolvedHost = server.config.server.host\n const addr = server.httpServer?.address()\n return {\n host: typeof resolvedHost === 'string' ? resolvedHost : 'localhost',\n port: typeof addr === 'object' && addr ? addr.port : server.config.server.port,\n }\n}\n\n/**\n * Register the dev server in the registry and watch its config for manifest +\n * interface changes. The workbench reads the entry to locate and render the\n * server; the watcher keeps it current as `sanity.cli.ts` is edited.\n */\nexport async function startDevServerRegistration(\n options: DevServerRegistrationOptions,\n): Promise<DevServerRegistrationHandle> {\n const {cliConfig, extractManifest, isApp, onInterfaceSetChange, output, server, workDir} = options\n\n const {host: appHost, port: appPort} = serverAddress(server)\n\n reportConfigErrors(cliConfig.app, output)\n\n // Forwarded alongside (not inside) the manifest so the workbench renders local\n // panels/workers and reads the configs without a deploy.\n const interfaces = deriveInterfaces(cliConfig.app, {isApp})\n const configs = await deriveConfigs(cliConfig)\n\n const workbenchApp = isWorkbenchApp(cliConfig.app) ? cliConfig.app : undefined\n const config = resolveWorkbenchConfig(cliConfig)\n // A config runs alongside the app it configures, so give it its own id\n // namespace — sharing the app's slug would make the two indistinguishable here.\n const id = config ? `config:${config.appType}` : workbenchApp?.slug\n // Identity is resolved and the reference composed here, so the workbench reads\n // both off the registry entry instead of recomposing them. Name defaults to the\n // slug, mirroring brett.\n const name = workbenchApp?.name ?? workbenchApp?.slug\n const reference =\n workbenchApp && name\n ? // No workbench app is a singleton now that the only one (the Media Library)\n // is a config, not an app — so its reference is always `<org>/<name>`.\n applicationReference({\n isSingleton: false,\n name,\n organizationId: workbenchApp.organizationId,\n })\n : undefined\n\n // Separate namespaces mean a shared id is a genuine duplicate, so the gate is\n // a plain id match — no config-vs-app role left to reconcile.\n const devServer = id ? getRegisteredServers().find((server) => server.id === id) : undefined\n\n if (id && devServer) {\n output.error(\n `\"${id}\" is already served by another dev server running on port ${devServer.port}, ` +\n \"so the workbench can't tell them apart and this one stays out of it. Stop that server first.\",\n {exit: false},\n )\n return {close: async () => {}}\n }\n\n const registration = registerDevServer({\n configs,\n host: appHost,\n id,\n interfaces,\n name,\n port: appPort,\n projectId: cliConfig?.api?.projectId,\n reference,\n type: isApp ? 'coreApp' : 'studio',\n workDir,\n })\n\n const exposesSet = trackExposesSet({configs, interfaces})\n\n const watcher = await startDevManifestWatcher({\n // Re-derive every pass (don't omit): the registry patch is a shallow merge,\n // so omitting would wipe the registered set.\n extract: async (params) => {\n const nextConfig = await getCliConfigUncached(params.workDir)\n reportConfigErrors(nextConfig.app, output)\n return {\n configs: await deriveConfigs(nextConfig),\n interfaces: deriveInterfaces(nextConfig.app, {isApp}),\n manifest: await extractManifest(params),\n }\n },\n // A studio's root resolves to `sanity.config.*` but its interfaces live in\n // `sanity.cli.*` — watch that too. Apps already root at `sanity.cli.*`.\n extraWatchFilenames: isApp ? undefined : ['sanity.cli.js', 'sanity.cli.ts'],\n output,\n update: async (patch) => {\n if (\n !exposesSet.changed({\n configs: patch.configs,\n interfaces: patch.interfaces,\n })\n ) {\n registration.update(patch)\n return\n }\n // Rebuild the remote *before* patching the registry — the patch reloads the\n // page, which must re-fetch a remote that already exposes the new interface.\n const rebuiltServer = await onInterfaceSetChange?.()\n // Commit only after a successful rebuild, so a thrown one retries next pass.\n exposesSet.commit({\n configs: patch.configs,\n interfaces: patch.interfaces,\n })\n // The recreated server can bind a different port (non-strict ports).\n registration.update(rebuiltServer ? {...patch, ...serverAddress(rebuiltServer)} : patch)\n },\n workDir,\n })\n\n return {\n close: async () => {\n registration.release()\n await watcher.close()\n },\n }\n}\n"],"names":["getCliConfigUncached","applicationReference","isWorkbenchApp","isWorkbenchConfig","deriveInterfaces","resolveWorkbenchConfig","formatWorkbenchAppErrors","validateWorkbenchApp","deriveConfigs","trackExposesSet","getRegisteredServers","registerDevServer","startDevManifestWatcher","reportConfigErrors","app","output","errors","length","warn","serverAddress","server","resolvedHost","config","host","addr","httpServer","address","port","startDevServerRegistration","options","cliConfig","extractManifest","isApp","onInterfaceSetChange","workDir","appHost","appPort","interfaces","configs","workbenchApp","undefined","id","appType","slug","name","reference","isSingleton","organizationId","devServer","find","error","exit","close","registration","projectId","api","type","exposesSet","watcher","extract","params","nextConfig","manifest","extraWatchFilenames","update","patch","changed","rebuiltServer","commit","release"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/dev/startDevServerRegistration.ts"],"sourcesContent":["import {type CliConfig, getCliConfigUncached, type Output} from '@sanity/cli-core'\nimport {type ViteDevServer} from 'vite'\n\nimport {applicationReference} from '../../applicationReference.js'\nimport {isWorkbenchApp, isWorkbenchConfig} from '../../defineApp.js'\nimport {deriveInterfaces} from '../../deriveInterfaces.js'\nimport {resolveWorkbenchConfig} from '../../resolveWorkbenchConfig.js'\nimport {formatWorkbenchAppErrors, validateWorkbenchApp} from '../../validateWorkbenchApp.js'\nimport {deriveConfigs} from './deriveConfigs.js'\nimport {trackExposesSet} from './exposesSetId.js'\nimport {type DevServerManifest, getRegisteredServers, registerDevServer} from './registry.js'\nimport {startDevManifestWatcher} from './startDevManifestWatcher.js'\n\ninterface DevServerRegistrationOptions {\n cliConfig: CliConfig\n /**\n * Extract the project manifest to inline into the registry. The caller owns the\n * studio-vs-app split (manifest formats are CLI-domain); registration re-derives\n * the interface set alongside it.\n */\n extractManifest: (params: {\n applicationId?: string\n configPath: string\n workDir: string\n }) => Promise<DevServerManifest['manifest']>\n isApp: boolean\n output: Output\n server: ViteDevServer\n workDir: string\n\n /**\n * Rebuild the app's federation remote when its interface set changes, awaited\n * *before* the registry patch — the patch reloads the workbench page, which must\n * re-fetch a remote that already exposes the new interface. Resolves with the\n * recreated server so the entry gets its actual address (non-strict ports may\n * shift it); must reject if the restart produces no server, so the set stays\n * uncommitted and the next save retries instead of advertising a dead port.\n */\n onInterfaceSetChange?: () => Promise<ViteDevServer>\n}\n\ninterface DevServerRegistrationHandle {\n close: () => Promise<void>\n}\n\n/**\n * Log any app validation errors without aborting. Unlike build and deploy, dev\n * stays up on an invalid app so the author sees the errors and fixes them live on\n * the next save. A config is not an app — it isn't validated by the app schema\n * (which would spuriously demand a slug/title), so skip it here.\n */\nfunction reportConfigErrors(app: CliConfig['app'], output: Output): void {\n if (isWorkbenchConfig(app)) return\n const errors = validateWorkbenchApp(app)\n if (errors.length === 0) return\n output.warn(formatWorkbenchAppErrors(errors))\n}\n\n/** The address the server actually bound — the live socket, which can differ from the configured port under non-strict ports. */\nfunction serverAddress(server: ViteDevServer) {\n const resolvedHost = server.config.server.host\n const addr = server.httpServer?.address()\n return {\n host: typeof resolvedHost === 'string' ? resolvedHost : 'localhost',\n port: typeof addr === 'object' && addr ? addr.port : server.config.server.port,\n }\n}\n\n/**\n * Register the dev server in the registry and watch its config for manifest +\n * interface changes. The workbench reads the entry to locate and render the\n * server; the watcher keeps it current as `sanity.cli.ts` is edited.\n */\nexport async function startDevServerRegistration(\n options: DevServerRegistrationOptions,\n): Promise<DevServerRegistrationHandle> {\n const {cliConfig, extractManifest, isApp, onInterfaceSetChange, output, server, workDir} = options\n\n const {host: appHost, port: appPort} = serverAddress(server)\n\n reportConfigErrors(cliConfig.app, output)\n\n // Forwarded alongside (not inside) the manifest so the workbench renders local\n // panels/workers and reads the configs without a deploy.\n const interfaces = deriveInterfaces(cliConfig.app, {isApp})\n const configs = await deriveConfigs(cliConfig)\n\n const workbenchApp = isWorkbenchApp(cliConfig.app) ? cliConfig.app : undefined\n const config = resolveWorkbenchConfig(cliConfig)\n // A config runs alongside the app it configures, so give it its own id\n // namespace — sharing the app's slug would make the two indistinguishable here.\n const id = config ? `config:${config.appType}` : workbenchApp?.slug\n // Identity is resolved and the reference composed here, so the workbench reads\n // both off the registry entry instead of recomposing them. Name defaults to the\n // slug, mirroring brett.\n const name = workbenchApp?.name ?? workbenchApp?.slug\n const reference =\n workbenchApp && name\n ? // No workbench app is a singleton now that the only one (the Media Library)\n // is a config, not an app — so its reference is always `<org>/<name>`.\n applicationReference({\n isSingleton: false,\n name,\n organizationId: workbenchApp.organizationId,\n })\n : undefined\n\n // Separate namespaces mean a shared id is a genuine duplicate, so the gate is\n // a plain id match — no config-vs-app role left to reconcile.\n const devServer = id ? getRegisteredServers().find((server) => server.id === id) : undefined\n\n if (id && devServer) {\n output.error(\n `\"${id}\" is already served by another dev server running on port ${devServer.port}, ` +\n \"so the workbench can't tell them apart and this one stays out of it. Stop that server first.\",\n {exit: false},\n )\n return {close: async () => {}}\n }\n\n const registration = registerDevServer({\n configs,\n host: appHost,\n id,\n interfaces,\n name,\n port: appPort,\n projectId: cliConfig?.api?.projectId,\n reference,\n type: isApp ? 'coreApp' : 'studio',\n workDir,\n })\n\n const exposesSet = trackExposesSet({configs, interfaces})\n\n const watcher = await startDevManifestWatcher({\n // Re-derive every pass (don't omit): the registry patch is a shallow merge,\n // so omitting would wipe the registered set.\n extract: async (params) => {\n const nextConfig = await getCliConfigUncached(params.workDir)\n reportConfigErrors(nextConfig.app, output)\n return {\n configs: await deriveConfigs(nextConfig),\n interfaces: deriveInterfaces(nextConfig.app, {isApp}),\n manifest: await extractManifest({...params, applicationId: id}),\n }\n },\n // A studio's root resolves to `sanity.config.*` but its interfaces live in\n // `sanity.cli.*` — watch that too. Apps already root at `sanity.cli.*`.\n extraWatchFilenames: isApp ? undefined : ['sanity.cli.js', 'sanity.cli.ts'],\n output,\n update: async (patch) => {\n if (\n !exposesSet.changed({\n configs: patch.configs,\n interfaces: patch.interfaces,\n })\n ) {\n registration.update(patch)\n return\n }\n // Rebuild the remote *before* patching the registry — the patch reloads the\n // page, which must re-fetch a remote that already exposes the new interface.\n const rebuiltServer = await onInterfaceSetChange?.()\n // Commit only after a successful rebuild, so a thrown one retries next pass.\n exposesSet.commit({\n configs: patch.configs,\n interfaces: patch.interfaces,\n })\n // The recreated server can bind a different port (non-strict ports).\n registration.update(rebuiltServer ? {...patch, ...serverAddress(rebuiltServer)} : patch)\n },\n workDir,\n })\n\n return {\n close: async () => {\n registration.release()\n await watcher.close()\n },\n }\n}\n"],"names":["getCliConfigUncached","applicationReference","isWorkbenchApp","isWorkbenchConfig","deriveInterfaces","resolveWorkbenchConfig","formatWorkbenchAppErrors","validateWorkbenchApp","deriveConfigs","trackExposesSet","getRegisteredServers","registerDevServer","startDevManifestWatcher","reportConfigErrors","app","output","errors","length","warn","serverAddress","server","resolvedHost","config","host","addr","httpServer","address","port","startDevServerRegistration","options","cliConfig","extractManifest","isApp","onInterfaceSetChange","workDir","appHost","appPort","interfaces","configs","workbenchApp","undefined","id","appType","slug","name","reference","isSingleton","organizationId","devServer","find","error","exit","close","registration","projectId","api","type","exposesSet","watcher","extract","params","nextConfig","manifest","applicationId","extraWatchFilenames","update","patch","changed","rebuiltServer","commit","release"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/dev/startWorkbenchDev.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, type Output} from '@sanity/cli-core'\n\nimport {createServerLifecycle, toDisplayHost} from '../../util/serverOrchestration.js'\nimport {type AppServerResult, startAppServerSupervisor} from './appServerSupervisor.js'\nimport {type DevServerManifest} from './registry.js'\nimport {startDevServerRegistration} from './startDevServerRegistration.js'\nimport {\n startWorkbenchDevServer,\n startWorkbenchRemoteCoordinator,\n} from './startWorkbenchDevServer.js'\n\nexport interface StartWorkbenchDevOptions {\n /** Directory for the workbench Vite server's dependency cache. */\n cacheDir: string\n /** CLI-domain `app.id`/`deployment.appId` deprecation check, run before registering. */\n checkForDeprecatedAppId: () => void\n cliConfig: CliConfig\n /** Extract the project manifest to inline into the registry (studio-vs-app handled by the CLI). */\n extractManifest: (params: {\n configPath: string\n workDir: string\n }) => Promise<DevServerManifest['manifest']>\n httpHost: string | undefined\n httpPort: number\n isApp: boolean\n output: Output\n reactStrictMode: boolean\n /** Start the app/studio dev server — the CLI owns the server, this orchestrates it. */\n startAppServer: (params: {\n announceUrl: boolean\n cliConfig: CliConfig\n httpPort: number\n }) => Promise<AppServerResult>\n workDir: string\n}\n\n/**\n * Orchestrate the dev servers a workbench project needs: a singleton workbench\n * Vite server plus the app/studio dev server it renders, wired to the dev-server\n * registry so view/service edits re-sync live.\n *\n * A running workbench claims the configured port, so the app server binds the\n * next one. If the workbench can't start (package or port unavailable), the app\n * server falls back to the configured port and announces its own URL, exactly as\n * a plain `sanity dev` would.\n */\nexport async function startWorkbenchDev(\n options: StartWorkbenchDevOptions,\n): Promise<{close: () => Promise<void>}> {\n const {\n cacheDir,\n checkForDeprecatedAppId,\n cliConfig,\n extractManifest,\n httpHost,\n httpPort,\n isApp,\n output,\n reactStrictMode,\n startAppServer,\n workDir,\n } = options\n\n // The remote can't render itself, so it runs as a plain app server (not the\n // shell) that still claims the lock and bridges the registry, so app\n // `sanity dev`s register into it.\n if (process.env.SANITY_INTERNAL_IS_WORKBENCH_REMOTE === 'true') {\n const remote = await startAppServer({announceUrl: true, cliConfig, httpPort})\n if (!remote.started) return {close: async () => {}}\n\n const addr = remote.server.httpServer?.address()\n const port =\n (typeof addr === 'object' && addr ? addr.port : remote.server.config.server.port) ?? httpPort\n const coordinator = startWorkbenchRemoteCoordinator({httpHost, port, server: remote.server})\n\n return {\n close: async () => {\n await coordinator.close()\n await remote.close()\n },\n }\n }\n\n // Unwound in reverse on any failure or on close(): the watcher stops before\n // the app server, and the supervisor waits out an in-flight rebuild.\n const {close, closers, installSignalHandlers} = createServerLifecycle()\n\n const workbench = await startWorkbenchDevServer({\n cacheDir,\n cliConfig,\n httpHost,\n httpPort,\n mode: 'development',\n output,\n reactStrictMode,\n workDir,\n })\n closers.push(workbench.close)\n\n // A running workbench owns the configured port; the app server takes the next.\n // Without one it claims the configured port and announces its own URL.\n const appPort = workbench.workbenchAvailable ? workbench.workbenchPort + 1 : httpPort\n const announceUrl = !workbench.workbenchAvailable\n\n const supervised = await startAppServerSupervisor({\n cliConfig,\n start: (config) => startAppServer({announceUrl, cliConfig: config, httpPort: appPort}),\n workDir,\n }).catch(async (err) => {\n await close()\n throw err\n })\n\n if (!supervised.started) {\n // The app server already reported why (e.g. missing organization id). Hand\n // back a close that releases the workbench lock; nothing else came up.\n return {close}\n }\n const {supervisor} = supervised\n closers.push(supervisor.close)\n\n try {\n // The deprecated-id check and manifest extractor are CLI-domain, injected here.\n checkForDeprecatedAppId()\n const registration = await startDevServerRegistration({\n cliConfig,\n extractManifest,\n isApp,\n onInterfaceSetChange: () => supervisor.rebuild(),\n output,\n server: supervisor.server,\n workDir,\n })\n closers.push(registration.close)\n } catch (err) {\n // Registration runs after both servers are up; a failure here would leak the\n // workbench lock and dev servers without this teardown.\n await close()\n throw err\n }\n\n if (workbench.workbenchAvailable) {\n const workbenchUrl = `http://${toDisplayHost(workbench.httpHost)}:${workbench.workbenchPort}`\n const addr = supervisor.server.httpServer?.address()\n const port = typeof addr === 'object' && addr ? addr.port : supervisor.server.config.server.port\n output.log(\n `Workbench dev server started at ${styleText(['blue', 'underline'], workbenchUrl)} (app on port ${port})`,\n )\n }\n\n installSignalHandlers()\n\n return {close}\n}\n"],"names":["styleText","createServerLifecycle","toDisplayHost","startAppServerSupervisor","startDevServerRegistration","startWorkbenchDevServer","startWorkbenchRemoteCoordinator","startWorkbenchDev","options","cacheDir","checkForDeprecatedAppId","cliConfig","extractManifest","httpHost","httpPort","isApp","output","reactStrictMode","startAppServer","workDir","process","env","SANITY_INTERNAL_IS_WORKBENCH_REMOTE","remote","announceUrl","started","close","addr","server","httpServer","address","port","config","coordinator","closers","installSignalHandlers","workbench","mode","push","appPort","workbenchAvailable","workbenchPort","supervised","start","catch","err","supervisor","registration","onInterfaceSetChange","rebuild","workbenchUrl","log"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/dev/startWorkbenchDev.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, type Output} from '@sanity/cli-core'\n\nimport {createServerLifecycle, toDisplayHost} from '../../util/serverOrchestration.js'\nimport {type AppServerResult, startAppServerSupervisor} from './appServerSupervisor.js'\nimport {type DevServerManifest} from './registry.js'\nimport {startDevServerRegistration} from './startDevServerRegistration.js'\nimport {\n startWorkbenchDevServer,\n startWorkbenchRemoteCoordinator,\n} from './startWorkbenchDevServer.js'\n\nexport interface StartWorkbenchDevOptions {\n /** Directory for the workbench Vite server's dependency cache. */\n cacheDir: string\n /** CLI-domain `app.id`/`deployment.appId` deprecation check, run before registering. */\n checkForDeprecatedAppId: () => void\n cliConfig: CliConfig\n /** Extract the project manifest to inline into the registry (studio-vs-app handled by the CLI). */\n extractManifest: (params: {\n applicationId?: string\n configPath: string\n workDir: string\n }) => Promise<DevServerManifest['manifest']>\n httpHost: string | undefined\n httpPort: number\n isApp: boolean\n output: Output\n reactStrictMode: boolean\n /** Start the app/studio dev server — the CLI owns the server, this orchestrates it. */\n startAppServer: (params: {\n announceUrl: boolean\n cliConfig: CliConfig\n httpPort: number\n }) => Promise<AppServerResult>\n workDir: string\n}\n\n/**\n * Orchestrate the dev servers a workbench project needs: a singleton workbench\n * Vite server plus the app/studio dev server it renders, wired to the dev-server\n * registry so view/service edits re-sync live.\n *\n * A running workbench claims the configured port, so the app server binds the\n * next one. If the workbench can't start (package or port unavailable), the app\n * server falls back to the configured port and announces its own URL, exactly as\n * a plain `sanity dev` would.\n */\nexport async function startWorkbenchDev(\n options: StartWorkbenchDevOptions,\n): Promise<{close: () => Promise<void>}> {\n const {\n cacheDir,\n checkForDeprecatedAppId,\n cliConfig,\n extractManifest,\n httpHost,\n httpPort,\n isApp,\n output,\n reactStrictMode,\n startAppServer,\n workDir,\n } = options\n\n // The remote can't render itself, so it runs as a plain app server (not the\n // shell) that still claims the lock and bridges the registry, so app\n // `sanity dev`s register into it.\n if (process.env.SANITY_INTERNAL_IS_WORKBENCH_REMOTE === 'true') {\n const remote = await startAppServer({announceUrl: true, cliConfig, httpPort})\n if (!remote.started) return {close: async () => {}}\n\n const addr = remote.server.httpServer?.address()\n const port =\n (typeof addr === 'object' && addr ? addr.port : remote.server.config.server.port) ?? httpPort\n const coordinator = startWorkbenchRemoteCoordinator({httpHost, port, server: remote.server})\n\n return {\n close: async () => {\n await coordinator.close()\n await remote.close()\n },\n }\n }\n\n // Unwound in reverse on any failure or on close(): the watcher stops before\n // the app server, and the supervisor waits out an in-flight rebuild.\n const {close, closers, installSignalHandlers} = createServerLifecycle()\n\n const workbench = await startWorkbenchDevServer({\n cacheDir,\n cliConfig,\n httpHost,\n httpPort,\n mode: 'development',\n output,\n reactStrictMode,\n workDir,\n })\n closers.push(workbench.close)\n\n // A running workbench owns the configured port; the app server takes the next.\n // Without one it claims the configured port and announces its own URL.\n const appPort = workbench.workbenchAvailable ? workbench.workbenchPort + 1 : httpPort\n const announceUrl = !workbench.workbenchAvailable\n\n const supervised = await startAppServerSupervisor({\n cliConfig,\n start: (config) => startAppServer({announceUrl, cliConfig: config, httpPort: appPort}),\n workDir,\n }).catch(async (err) => {\n await close()\n throw err\n })\n\n if (!supervised.started) {\n // The app server already reported why (e.g. missing organization id). Hand\n // back a close that releases the workbench lock; nothing else came up.\n return {close}\n }\n const {supervisor} = supervised\n closers.push(supervisor.close)\n\n try {\n // The deprecated-id check and manifest extractor are CLI-domain, injected here.\n checkForDeprecatedAppId()\n const registration = await startDevServerRegistration({\n cliConfig,\n extractManifest,\n isApp,\n onInterfaceSetChange: () => supervisor.rebuild(),\n output,\n server: supervisor.server,\n workDir,\n })\n closers.push(registration.close)\n } catch (err) {\n // Registration runs after both servers are up; a failure here would leak the\n // workbench lock and dev servers without this teardown.\n await close()\n throw err\n }\n\n if (workbench.workbenchAvailable) {\n const workbenchUrl = `http://${toDisplayHost(workbench.httpHost)}:${workbench.workbenchPort}`\n const addr = supervisor.server.httpServer?.address()\n const port = typeof addr === 'object' && addr ? addr.port : supervisor.server.config.server.port\n output.log(\n `Workbench dev server started at ${styleText(['blue', 'underline'], workbenchUrl)} (app on port ${port})`,\n )\n }\n\n installSignalHandlers()\n\n return {close}\n}\n"],"names":["styleText","createServerLifecycle","toDisplayHost","startAppServerSupervisor","startDevServerRegistration","startWorkbenchDevServer","startWorkbenchRemoteCoordinator","startWorkbenchDev","options","cacheDir","checkForDeprecatedAppId","cliConfig","extractManifest","httpHost","httpPort","isApp","output","reactStrictMode","startAppServer","workDir","process","env","SANITY_INTERNAL_IS_WORKBENCH_REMOTE","remote","announceUrl","started","close","addr","server","httpServer","address","port","config","coordinator","closers","installSignalHandlers","workbench","mode","push","appPort","workbenchAvailable","workbenchPort","supervised","start","catch","err","supervisor","registration","onInterfaceSetChange","rebuild","workbenchUrl","log"],"mappings":"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"}
@@ -64,6 +64,7 @@ import { serveBuiltApplication } from './serveBuiltApplication.js';
64
64
  isApp
65
65
  }),
66
66
  manifest: await extractManifest({
67
+ applicationId: id,
67
68
  configPath,
68
69
  workDir
69
70
  }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/preview/startWorkbenchPreview.ts"],"sourcesContent":["import {readFile} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {type CliConfig, findProjectRoot, type Output} from '@sanity/cli-core'\n\nimport {buildAppId, SANITY_APP_ID_FILE} from '../../appId.js'\nimport {deriveInterfaces} from '../../deriveInterfaces.js'\nimport {resolveWorkbenchApp} from '../../resolveWorkbenchApp.js'\nimport {createServerLifecycle, toDisplayHost} from '../../util/serverOrchestration.js'\nimport {deriveConfigs} from '../dev/deriveConfigs.js'\nimport {type DevServerManifest, registerDevServer} from '../dev/registry.js'\nimport {startWorkbenchDevServer} from '../dev/startWorkbenchDevServer.js'\nimport {serveBuiltApplication} from './serveBuiltApplication.js'\n\nexport interface StartWorkbenchPreviewOptions {\n /** Directory for the workbench Vite server's dependency cache. */\n cacheDir: string\n /** CLI-domain `app.id`/`deployment.appId` deprecation check, run before registering. */\n checkForDeprecatedAppId: () => void\n cliConfig: CliConfig\n /** Extract the project manifest to inline into the registry (studio-vs-app handled by the CLI). */\n extractManifest: (params: {\n configPath: string\n workDir: string\n }) => Promise<DevServerManifest['manifest']>\n httpHost: string\n httpPort: number\n isApp: boolean\n /** The built `dist` directory to serve as the federation remote. */\n outDir: string\n output: Output\n reactStrictMode: boolean\n workDir: string\n}\n\n/**\n * `sanity start` for a workbench app: serve a production build the way dev serves\n * a live one. The same singleton workbench shell renders it and the same registry\n * advertises it — only the remote differs, static files from the build output\n * instead of a live Vite dev server. There's no config watcher or rebuild: a\n * build is fixed, so nothing re-syncs.\n *\n * A running workbench claims the configured port, so the built remote binds the\n * next one. Without one the remote takes the configured port and announces its\n * own URL.\n */\nexport async function startWorkbenchPreview(\n options: StartWorkbenchPreviewOptions,\n): Promise<{close: () => Promise<void>}> {\n const {\n cacheDir,\n checkForDeprecatedAppId,\n cliConfig,\n extractManifest,\n httpHost,\n httpPort,\n isApp,\n outDir,\n output,\n reactStrictMode,\n workDir,\n } = options\n\n const {close, closers, installSignalHandlers} = createServerLifecycle()\n\n const workbench = await startWorkbenchDevServer({\n cacheDir,\n cliConfig,\n httpHost,\n httpPort,\n mode: 'preview',\n output,\n reactStrictMode,\n workDir,\n })\n closers.push(workbench.close)\n\n const remotePort = workbench.workbenchAvailable ? workbench.workbenchPort + 1 : httpPort\n\n const remote = await serveBuiltApplication({\n cacheDir,\n httpHost,\n httpPort: remotePort,\n outDir,\n workDir,\n }).catch(async (err) => {\n await close()\n throw err\n })\n closers.push(remote.close)\n\n try {\n // Callers provide CLI-only validation and manifest extraction to keep them\n // out of workbench-cli.\n checkForDeprecatedAppId()\n const configPath = (await findProjectRoot(workDir)).path\n const workbench = resolveWorkbenchApp(cliConfig)\n\n if (!workbench) throw new Error('`sanity start` was invoked in a non-workbench application')\n const inlinedId = await readInlinedAppId(outDir)\n const configs = await deriveConfigs(cliConfig)\n const id = inlinedId ?? (await buildAppId(workbench))\n const registration = registerDevServer({\n configs,\n host: remote.host,\n id,\n interfaces: deriveInterfaces(cliConfig.app, {isApp}),\n manifest: await extractManifest({configPath, workDir}),\n manifestUpdatedAt: new Date().toISOString(),\n port: remote.port,\n projectId: cliConfig?.api?.projectId,\n type: isApp ? 'coreApp' : 'studio',\n workDir,\n })\n closers.push(async () => registration.release())\n } catch (err) {\n await close()\n throw err\n }\n\n if (workbench.workbenchAvailable) {\n const workbenchUrl = `http://${toDisplayHost(workbench.httpHost)}:${workbench.workbenchPort}`\n output.log(\n `Workbench preview server started at ${styleText(['blue', 'underline'], workbenchUrl)} (serving build on port ${remote.port})`,\n )\n } else {\n const remoteUrl = `http://${toDisplayHost(remote.host)}:${remote.port}`\n output.log(`Serving build at ${styleText(['blue', 'underline'], remoteUrl)}`)\n }\n\n installSignalHandlers()\n\n return {close}\n}\n\n/** The id the build inlined into its bundle, or undefined when absent. */\nasync function readInlinedAppId(outDir: string): Promise<string | undefined> {\n try {\n return (await readFile(path.join(outDir, SANITY_APP_ID_FILE), 'utf8')).trim() || undefined\n } catch {\n return undefined\n }\n}\n"],"names":["readFile","path","styleText","findProjectRoot","buildAppId","SANITY_APP_ID_FILE","deriveInterfaces","resolveWorkbenchApp","createServerLifecycle","toDisplayHost","deriveConfigs","registerDevServer","startWorkbenchDevServer","serveBuiltApplication","startWorkbenchPreview","options","cacheDir","checkForDeprecatedAppId","cliConfig","extractManifest","httpHost","httpPort","isApp","outDir","output","reactStrictMode","workDir","close","closers","installSignalHandlers","workbench","mode","push","remotePort","workbenchAvailable","workbenchPort","remote","catch","err","configPath","Error","inlinedId","readInlinedAppId","configs","id","registration","host","interfaces","app","manifest","manifestUpdatedAt","Date","toISOString","port","projectId","api","type","release","workbenchUrl","log","remoteUrl","join","trim","undefined"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/preview/startWorkbenchPreview.ts"],"sourcesContent":["import {readFile} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {type CliConfig, findProjectRoot, type Output} from '@sanity/cli-core'\n\nimport {buildAppId, SANITY_APP_ID_FILE} from '../../appId.js'\nimport {deriveInterfaces} from '../../deriveInterfaces.js'\nimport {resolveWorkbenchApp} from '../../resolveWorkbenchApp.js'\nimport {createServerLifecycle, toDisplayHost} from '../../util/serverOrchestration.js'\nimport {deriveConfigs} from '../dev/deriveConfigs.js'\nimport {type DevServerManifest, registerDevServer} from '../dev/registry.js'\nimport {startWorkbenchDevServer} from '../dev/startWorkbenchDevServer.js'\nimport {serveBuiltApplication} from './serveBuiltApplication.js'\n\nexport interface StartWorkbenchPreviewOptions {\n /** Directory for the workbench Vite server's dependency cache. */\n cacheDir: string\n /** CLI-domain `app.id`/`deployment.appId` deprecation check, run before registering. */\n checkForDeprecatedAppId: () => void\n cliConfig: CliConfig\n /** Extract the project manifest to inline into the registry (studio-vs-app handled by the CLI). */\n extractManifest: (params: {\n applicationId?: string\n configPath: string\n workDir: string\n }) => Promise<DevServerManifest['manifest']>\n httpHost: string\n httpPort: number\n isApp: boolean\n /** The built `dist` directory to serve as the federation remote. */\n outDir: string\n output: Output\n reactStrictMode: boolean\n workDir: string\n}\n\n/**\n * `sanity start` for a workbench app: serve a production build the way dev serves\n * a live one. The same singleton workbench shell renders it and the same registry\n * advertises it — only the remote differs, static files from the build output\n * instead of a live Vite dev server. There's no config watcher or rebuild: a\n * build is fixed, so nothing re-syncs.\n *\n * A running workbench claims the configured port, so the built remote binds the\n * next one. Without one the remote takes the configured port and announces its\n * own URL.\n */\nexport async function startWorkbenchPreview(\n options: StartWorkbenchPreviewOptions,\n): Promise<{close: () => Promise<void>}> {\n const {\n cacheDir,\n checkForDeprecatedAppId,\n cliConfig,\n extractManifest,\n httpHost,\n httpPort,\n isApp,\n outDir,\n output,\n reactStrictMode,\n workDir,\n } = options\n\n const {close, closers, installSignalHandlers} = createServerLifecycle()\n\n const workbench = await startWorkbenchDevServer({\n cacheDir,\n cliConfig,\n httpHost,\n httpPort,\n mode: 'preview',\n output,\n reactStrictMode,\n workDir,\n })\n closers.push(workbench.close)\n\n const remotePort = workbench.workbenchAvailable ? workbench.workbenchPort + 1 : httpPort\n\n const remote = await serveBuiltApplication({\n cacheDir,\n httpHost,\n httpPort: remotePort,\n outDir,\n workDir,\n }).catch(async (err) => {\n await close()\n throw err\n })\n closers.push(remote.close)\n\n try {\n // Callers provide CLI-only validation and manifest extraction to keep them\n // out of workbench-cli.\n checkForDeprecatedAppId()\n const configPath = (await findProjectRoot(workDir)).path\n const workbench = resolveWorkbenchApp(cliConfig)\n\n if (!workbench) throw new Error('`sanity start` was invoked in a non-workbench application')\n const inlinedId = await readInlinedAppId(outDir)\n const configs = await deriveConfigs(cliConfig)\n const id = inlinedId ?? (await buildAppId(workbench))\n const registration = registerDevServer({\n configs,\n host: remote.host,\n id,\n interfaces: deriveInterfaces(cliConfig.app, {isApp}),\n manifest: await extractManifest({applicationId: id, configPath, workDir}),\n manifestUpdatedAt: new Date().toISOString(),\n port: remote.port,\n projectId: cliConfig?.api?.projectId,\n type: isApp ? 'coreApp' : 'studio',\n workDir,\n })\n closers.push(async () => registration.release())\n } catch (err) {\n await close()\n throw err\n }\n\n if (workbench.workbenchAvailable) {\n const workbenchUrl = `http://${toDisplayHost(workbench.httpHost)}:${workbench.workbenchPort}`\n output.log(\n `Workbench preview server started at ${styleText(['blue', 'underline'], workbenchUrl)} (serving build on port ${remote.port})`,\n )\n } else {\n const remoteUrl = `http://${toDisplayHost(remote.host)}:${remote.port}`\n output.log(`Serving build at ${styleText(['blue', 'underline'], remoteUrl)}`)\n }\n\n installSignalHandlers()\n\n return {close}\n}\n\n/** The id the build inlined into its bundle, or undefined when absent. */\nasync function readInlinedAppId(outDir: string): Promise<string | undefined> {\n try {\n return (await readFile(path.join(outDir, SANITY_APP_ID_FILE), 'utf8')).trim() || undefined\n } catch {\n return undefined\n }\n}\n"],"names":["readFile","path","styleText","findProjectRoot","buildAppId","SANITY_APP_ID_FILE","deriveInterfaces","resolveWorkbenchApp","createServerLifecycle","toDisplayHost","deriveConfigs","registerDevServer","startWorkbenchDevServer","serveBuiltApplication","startWorkbenchPreview","options","cacheDir","checkForDeprecatedAppId","cliConfig","extractManifest","httpHost","httpPort","isApp","outDir","output","reactStrictMode","workDir","close","closers","installSignalHandlers","workbench","mode","push","remotePort","workbenchAvailable","workbenchPort","remote","catch","err","configPath","Error","inlinedId","readInlinedAppId","configs","id","registration","host","interfaces","app","manifest","applicationId","manifestUpdatedAt","Date","toISOString","port","projectId","api","type","release","workbenchUrl","log","remoteUrl","join","trim","undefined"],"mappings":"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"}
package/dist/defineApp.js CHANGED
@@ -35,6 +35,7 @@ import { DockSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema } from
35
35
  * on a studio is rejected (studio app views are not yet implemented).
36
36
  */ entry: z.optional(z.string("must be a path to the app's entry file")),
37
37
  /** Optional icon override (path to an SVG). Wins over manifest/studio icon. */ icon: z.optional(z.string()),
38
+ /** Sanity-owned app deployed once and installed per org. @internal */ isSingleton: z.optional(z.boolean()),
38
39
  /**
39
40
  * Stable identity, distinct from the `slug` address. Defaults to `slug` when
40
41
  * omitted. Identity keys — the build id and derived interface ids — are built
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/defineApp.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\nimport {APP_SLUG_PATTERN} from './appSlug.js'\nimport {DockSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema} from './contract.js'\n\n/**\n * Dashboard visibility values. Mirrors `APP_VISIBILITIES` in `@sanity/cli-core`\n * (which can't be imported here — pulling the barrel into this lean module bloats\n * the config-load path). Kept in sync by a type test in `defineApp.test.ts`.\n */\nconst APP_VISIBILITIES = ['default', 'unlisted', 'disabled'] as const\n\n/**\n * Internal application discriminator. Sanity-owned singleton apps only;\n * validated by the schema but excluded from the public `DefineAppInput` type.\n */\nconst ApplicationType = z.enum(['coreApp', 'studio', 'canvas', 'dashboard'])\n\n/**\n * Runtime-validation schema for `defineApplication`.\n * @internal\n */\nexport const DefineAppInputSchema = z\n .object({\n /**\n * Internal — Sanity-owned singleton apps only. Validated here but excluded\n * from the public `DefineAppInput` type.\n * @internal\n */\n applicationType: z.optional(ApplicationType),\n /** Default placement inherited by panel and window views. */\n dock: z.optional(DockSchema),\n /**\n * App entrypoint module. Defaults to `./src/App.tsx` when omitted. The build\n * derives the app's navigable `app` view from it. SDK apps only — setting it\n * on a studio is rejected (studio app views are not yet implemented).\n */\n entry: z.optional(z.string(\"must be a path to the app's entry file\")),\n /** Optional icon override (path to an SVG). Wins over manifest/studio icon. */\n icon: z.optional(z.string()),\n /**\n * Stable identity, distinct from the `slug` address. Defaults to `slug` when\n * omitted. Identity keys — the build id and derived interface ids — are built\n * from this, so renaming the slug no longer changes identity.\n */\n name: z.optional(\n z\n .string()\n .check(\n z.regex(\n APP_SLUG_PATTERN,\n 'App `name` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric',\n ),\n ),\n ),\n /** Organization that owns the app — the workbench runs and deploys against it. */\n organizationId: z.string(\n \"App `organizationId` is required — pass the owning organization's ID to `defineApplication`\",\n ),\n slug: z\n .string('App `slug` is required — the hostname the application is created at on deploy')\n .check(\n z.regex(\n APP_SLUG_PATTERN,\n 'App `slug` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric',\n ),\n ),\n /** User-facing app title. Wins over studio.config.ts title on merge. */\n title: z.string(),\n /** Views the app exposes (e.g. a window, dock panels, and tiles). */\n views: z.optional(z.array(InterfaceDeclarationSchema, 'must be an array of views')),\n /** Dashboard visibility of the app. Defaults to `default` when omitted. */\n visibility: z.optional(z.enum(APP_VISIBILITIES)),\n /** Background web workers the app runs. */\n webWorkers: z.optional(z.array(ServiceDeclarationSchema, 'must be an array of web workers')),\n })\n .check(\n z.refine((input) => {\n const names = [\n ...(input.entry === undefined ? [] : [input.name ?? input.slug]),\n ...(input.views ?? []).map((view) => view.name),\n ...(input.webWorkers ?? []).map((webWorker) => webWorker.name),\n ]\n return new Set(names).size === names.length\n }, '`name` must be unique across views and web workers. Rename one of the duplicates.'),\n // Studio app views are not implemented yet. A studio that declares `entry`\n // (the SDK app-view entrypoint) is rejected here rather than silently\n // generating one; studios keep navigating via their existing render path.\n z.refine((input) => !(input.applicationType === 'studio' && input.entry !== undefined), {\n error: 'App views for studios are not implemented yet',\n path: ['entry'],\n }),\n )\n\n/**\n * User-facing input for `defineApplication`. Excludes the internal\n * `applicationType`.\n * @public\n */\nexport type DefineAppInput = Omit<z.output<typeof DefineAppInputSchema>, 'applicationType'>\n\n/**\n * Nominal brand the CLI discriminates on to enable the workbench build/deploy\n * codepath. Registered via `Symbol.for` so the marker survives module-realm\n * boundaries — `@sanity/cli-core` re-derives the same global symbol with\n * `Symbol.for` rather than importing it, so it stays internal to this module.\n */\nconst WORKBENCH_APP: unique symbol = Symbol.for('sanity.workbench.defineApp')\n\n/**\n * The branded result of `defineApplication`. Carries the same fields as the\n * input plus the internal brand — users only ever see `DefineAppInput`.\n * @public\n */\nexport type DefineAppResult = DefineAppInput & {readonly [WORKBENCH_APP]: true}\n\n/**\n * A branded app as the CLI reads it — the full schema shape, including the\n * internal fields `DefineAppInput` omits. Schema-derived so the narrowing\n * can't drift from what the schema validates.\n * @public\n */\nexport type WorkbenchApp = DefineAppResult & z.output<typeof DefineAppInputSchema>\n\n/**\n * Whether `app` is a branded `defineApplication(...)` result — the sole\n * workbench opt-in.\n * @public\n */\nexport function isWorkbenchApp(app: unknown): app is WorkbenchApp {\n return typeof app === 'object' && app !== null && WORKBENCH_APP in app\n}\n\n/**\n * Declare a Sanity Workbench application. Identity at runtime — returns the same\n * object reference, tagged with the workbench brand. Field validation (the\n * `slug` pattern etc.) runs at build time in the CLI via `DefineAppInputSchema`;\n * this helper stays a thin, pure identity wrapper.\n * @public\n */\nexport function defineApplication(input: DefineAppInput): DefineAppResult {\n return Object.defineProperty(input, WORKBENCH_APP, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n }) as DefineAppResult\n}\n\n/**\n * One custom field a media library exposes. `src` default-exports a `defineField(...)` schema type.\n * @public\n */\nexport interface MediaLibraryField {\n /** Unique within the media library. */\n name: string\n src: string\n title: string\n\n /** Readable outside the owning organization. */\n public?: boolean\n}\n\n/**\n * Sanity-owned singleton, so authors don't name or title the app — only `organizationId` is required.\n * @public\n */\nexport interface DefineMediaLibraryInput {\n /** Organization that owns the media library — the CLI runs and deploys against it. */\n organizationId: string\n\n fields?: MediaLibraryField[]\n}\n\n/**\n * Nominal brand the CLI discriminates a config on. A config is *not* an app: it\n * carries no `slug`/`title`/application identity, only a target `appType`, its\n * owning `organizationId`, and its `fields`. Registered via `Symbol.for` so the\n * marker survives module-realm boundaries — `@sanity/cli-core` re-derives the\n * same global symbol rather than importing it.\n */\nconst WORKBENCH_CONFIG: unique symbol = Symbol.for('sanity.workbench.defineConfig')\n\n/**\n * A branded workbench config as the CLI reads it: bound to its target app by\n * `appType`, not carrying its own app identity. The deploy/undeploy/build paths\n * discriminate it via {@link isWorkbenchConfig}.\n * @public\n */\nexport interface WorkbenchConfig {\n appType: 'media-library'\n fields: MediaLibraryField[]\n organizationId: string\n readonly [WORKBENCH_CONFIG]: true\n}\n\n/**\n * Whether `app` is a branded `unstable_defineMediaLibrary(...)` config — a\n * config-carrier rather than an app. Configs live in `cliConfig.app` alongside\n * apps but resolve through `resolveWorkbenchConfig`, not `resolveWorkbenchApp`.\n * @public\n */\nexport function isWorkbenchConfig(app: unknown): app is WorkbenchConfig {\n return typeof app === 'object' && app !== null && WORKBENCH_CONFIG in app\n}\n\n/**\n * Declare the Sanity Media Library config. The Media Library is a Sanity-owned\n * singleton, so this is not an app — it carries no slug or title, only the\n * target `appType`, its owning organization, and the `fields` it contributes to\n * the installation's config.\n * @public\n */\nexport function unstable_defineMediaLibrary(input: DefineMediaLibraryInput): WorkbenchConfig {\n return Object.defineProperty(\n {appType: 'media-library', fields: input.fields ?? [], organizationId: input.organizationId},\n WORKBENCH_CONFIG,\n {configurable: false, enumerable: false, value: true, writable: false},\n ) as WorkbenchConfig\n}\n"],"names":["z","APP_SLUG_PATTERN","DockSchema","InterfaceDeclarationSchema","ServiceDeclarationSchema","APP_VISIBILITIES","ApplicationType","enum","DefineAppInputSchema","object","applicationType","optional","dock","entry","string","icon","name","check","regex","organizationId","slug","title","views","array","visibility","webWorkers","refine","input","names","undefined","map","view","webWorker","Set","size","length","error","path","WORKBENCH_APP","Symbol","for","isWorkbenchApp","app","defineApplication","Object","defineProperty","configurable","enumerable","value","writable","WORKBENCH_CONFIG","isWorkbenchConfig","unstable_defineMediaLibrary","appType","fields"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/defineApp.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\nimport {APP_SLUG_PATTERN} from './appSlug.js'\nimport {DockSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema} from './contract.js'\n\n/**\n * Dashboard visibility values. Mirrors `APP_VISIBILITIES` in `@sanity/cli-core`\n * (which can't be imported here — pulling the barrel into this lean module bloats\n * the config-load path). Kept in sync by a type test in `defineApp.test.ts`.\n */\nconst APP_VISIBILITIES = ['default', 'unlisted', 'disabled'] as const\n\n/**\n * Internal application discriminator. Sanity-owned singleton apps only;\n * validated by the schema but excluded from the public `DefineAppInput` type.\n */\nconst ApplicationType = z.enum(['coreApp', 'studio', 'canvas', 'dashboard'])\n\n/**\n * Runtime-validation schema for `defineApplication`.\n * @internal\n */\nexport const DefineAppInputSchema = z\n .object({\n /**\n * Internal — Sanity-owned singleton apps only. Validated here but excluded\n * from the public `DefineAppInput` type.\n * @internal\n */\n applicationType: z.optional(ApplicationType),\n /** Default placement inherited by panel and window views. */\n dock: z.optional(DockSchema),\n /**\n * App entrypoint module. Defaults to `./src/App.tsx` when omitted. The build\n * derives the app's navigable `app` view from it. SDK apps only — setting it\n * on a studio is rejected (studio app views are not yet implemented).\n */\n entry: z.optional(z.string(\"must be a path to the app's entry file\")),\n /** Optional icon override (path to an SVG). Wins over manifest/studio icon. */\n icon: z.optional(z.string()),\n /** Sanity-owned app deployed once and installed per org. @internal */\n isSingleton: z.optional(z.boolean()),\n /**\n * Stable identity, distinct from the `slug` address. Defaults to `slug` when\n * omitted. Identity keys — the build id and derived interface ids — are built\n * from this, so renaming the slug no longer changes identity.\n */\n name: z.optional(\n z\n .string()\n .check(\n z.regex(\n APP_SLUG_PATTERN,\n 'App `name` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric',\n ),\n ),\n ),\n /** Organization that owns the app — the workbench runs and deploys against it. */\n organizationId: z.string(\n \"App `organizationId` is required — pass the owning organization's ID to `defineApplication`\",\n ),\n slug: z\n .string('App `slug` is required — the hostname the application is created at on deploy')\n .check(\n z.regex(\n APP_SLUG_PATTERN,\n 'App `slug` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric',\n ),\n ),\n /** User-facing app title. Wins over studio.config.ts title on merge. */\n title: z.string(),\n /** Views the app exposes (e.g. a window, dock panels, and tiles). */\n views: z.optional(z.array(InterfaceDeclarationSchema, 'must be an array of views')),\n /** Dashboard visibility of the app. Defaults to `default` when omitted. */\n visibility: z.optional(z.enum(APP_VISIBILITIES)),\n /** Background web workers the app runs. */\n webWorkers: z.optional(z.array(ServiceDeclarationSchema, 'must be an array of web workers')),\n })\n .check(\n z.refine((input) => {\n const names = [\n ...(input.entry === undefined ? [] : [input.name ?? input.slug]),\n ...(input.views ?? []).map((view) => view.name),\n ...(input.webWorkers ?? []).map((webWorker) => webWorker.name),\n ]\n return new Set(names).size === names.length\n }, '`name` must be unique across views and web workers. Rename one of the duplicates.'),\n // Studio app views are not implemented yet. A studio that declares `entry`\n // (the SDK app-view entrypoint) is rejected here rather than silently\n // generating one; studios keep navigating via their existing render path.\n z.refine((input) => !(input.applicationType === 'studio' && input.entry !== undefined), {\n error: 'App views for studios are not implemented yet',\n path: ['entry'],\n }),\n )\n\n/**\n * User-facing input for `defineApplication`. Excludes the internal\n * `applicationType` and `isSingleton`.\n * @public\n */\nexport type DefineAppInput = Omit<\n z.output<typeof DefineAppInputSchema>,\n 'applicationType' | 'isSingleton'\n>\n\n/**\n * Nominal brand the CLI discriminates on to enable the workbench build/deploy\n * codepath. Registered via `Symbol.for` so the marker survives module-realm\n * boundaries — `@sanity/cli-core` re-derives the same global symbol with\n * `Symbol.for` rather than importing it, so it stays internal to this module.\n */\nconst WORKBENCH_APP: unique symbol = Symbol.for('sanity.workbench.defineApp')\n\n/**\n * The branded result of `defineApplication`. Carries the same fields as the\n * input plus the internal brand — users only ever see `DefineAppInput`.\n * @public\n */\nexport type DefineAppResult = DefineAppInput & {readonly [WORKBENCH_APP]: true}\n\n/**\n * A branded app as the CLI reads it — the full schema shape, including the\n * internal fields `DefineAppInput` omits. Schema-derived so the narrowing\n * can't drift from what the schema validates.\n * @public\n */\nexport type WorkbenchApp = DefineAppResult & z.output<typeof DefineAppInputSchema>\n\n/**\n * Whether `app` is a branded `defineApplication(...)` result — the sole\n * workbench opt-in.\n * @public\n */\nexport function isWorkbenchApp(app: unknown): app is WorkbenchApp {\n return typeof app === 'object' && app !== null && WORKBENCH_APP in app\n}\n\n/**\n * Declare a Sanity Workbench application. Identity at runtime — returns the same\n * object reference, tagged with the workbench brand. Field validation (the\n * `slug` pattern etc.) runs at build time in the CLI via `DefineAppInputSchema`;\n * this helper stays a thin, pure identity wrapper.\n * @public\n */\nexport function defineApplication(input: DefineAppInput): DefineAppResult {\n return Object.defineProperty(input, WORKBENCH_APP, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n }) as DefineAppResult\n}\n\n/**\n * One custom field a media library exposes. `src` default-exports a `defineField(...)` schema type.\n * @public\n */\nexport interface MediaLibraryField {\n /** Unique within the media library. */\n name: string\n src: string\n title: string\n\n /** Readable outside the owning organization. */\n public?: boolean\n}\n\n/**\n * Sanity-owned singleton, so authors don't name or title the app — only `organizationId` is required.\n * @public\n */\nexport interface DefineMediaLibraryInput {\n /** Organization that owns the media library — the CLI runs and deploys against it. */\n organizationId: string\n\n fields?: MediaLibraryField[]\n}\n\n/**\n * Nominal brand the CLI discriminates a config on. A config is *not* an app: it\n * carries no `slug`/`title`/application identity, only a target `appType`, its\n * owning `organizationId`, and its `fields`. Registered via `Symbol.for` so the\n * marker survives module-realm boundaries — `@sanity/cli-core` re-derives the\n * same global symbol rather than importing it.\n */\nconst WORKBENCH_CONFIG: unique symbol = Symbol.for('sanity.workbench.defineConfig')\n\n/**\n * A branded workbench config as the CLI reads it: bound to its target app by\n * `appType`, not carrying its own app identity. The deploy/undeploy/build paths\n * discriminate it via {@link isWorkbenchConfig}.\n * @public\n */\nexport interface WorkbenchConfig {\n appType: 'media-library'\n fields: MediaLibraryField[]\n organizationId: string\n readonly [WORKBENCH_CONFIG]: true\n}\n\n/**\n * Whether `app` is a branded `unstable_defineMediaLibrary(...)` config — a\n * config-carrier rather than an app. Configs live in `cliConfig.app` alongside\n * apps but resolve through `resolveWorkbenchConfig`, not `resolveWorkbenchApp`.\n * @public\n */\nexport function isWorkbenchConfig(app: unknown): app is WorkbenchConfig {\n return typeof app === 'object' && app !== null && WORKBENCH_CONFIG in app\n}\n\n/**\n * Declare the Sanity Media Library config. The Media Library is a Sanity-owned\n * singleton, so this is not an app — it carries no slug or title, only the\n * target `appType`, its owning organization, and the `fields` it contributes to\n * the installation's config.\n * @public\n */\nexport function unstable_defineMediaLibrary(input: DefineMediaLibraryInput): WorkbenchConfig {\n return Object.defineProperty(\n {appType: 'media-library', fields: input.fields ?? [], organizationId: input.organizationId},\n WORKBENCH_CONFIG,\n {configurable: false, enumerable: false, value: true, writable: false},\n ) as WorkbenchConfig\n}\n"],"names":["z","APP_SLUG_PATTERN","DockSchema","InterfaceDeclarationSchema","ServiceDeclarationSchema","APP_VISIBILITIES","ApplicationType","enum","DefineAppInputSchema","object","applicationType","optional","dock","entry","string","icon","isSingleton","boolean","name","check","regex","organizationId","slug","title","views","array","visibility","webWorkers","refine","input","names","undefined","map","view","webWorker","Set","size","length","error","path","WORKBENCH_APP","Symbol","for","isWorkbenchApp","app","defineApplication","Object","defineProperty","configurable","enumerable","value","writable","WORKBENCH_CONFIG","isWorkbenchConfig","unstable_defineMediaLibrary","appType","fields"],"mappings":"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"}
@@ -21,6 +21,9 @@ import { formatWorkbenchAppErrors, validateWorkbenchApp } from './validateWorkbe
21
21
  applicationType: app.applicationType,
22
22
  entry: app.entry,
23
23
  icon: app.icon,
24
+ ...app.isSingleton === undefined ? {} : {
25
+ isSingleton: app.isSingleton
26
+ },
24
27
  // Identity defaults to the address, so existing apps behave identically.
25
28
  name: app.name ?? app.slug,
26
29
  organizationId: app.organizationId,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/resolveWorkbenchApp.ts"],"sourcesContent":["// Package-internal shared resolver: turn a CLI config's branded\n// `defineApplication` app into its declared interfaces, or `null` for a plain\n// project — and for a config (a branded `unstable_defineMediaLibrary`), which\n// is not an app. The build and deploy accessors (actions/build, actions/deploy)\n// each build their command-specific view on top of this one brand-check +\n// extraction, so the discrimination lives in exactly one place.\n\nimport {type AppVisibility, type CliConfig} from '@sanity/cli-core'\n\nimport {type WorkbenchConfigValue} from './contract.js'\nimport {type DefineAppInput, isWorkbenchApp} from './defineApp.js'\nimport {formatWorkbenchAppErrors, validateWorkbenchApp} from './validateWorkbenchApp.js'\n\n/**\n * Bundled so adding a declaration family touches this type and the artifact\n * expanders, not every hop of build/dev plumbing in between. `config` is sourced\n * from `resolveWorkbenchConfig` (a config is not an app), not from this resolver.\n * @internal\n */\nexport interface WorkbenchExposes {\n config?: WorkbenchConfigValue\n views?: DefineAppInput['views']\n webWorkers?: DefineAppInput['webWorkers']\n}\n\n/** @public */\nexport interface ResolvedWorkbenchApp {\n /**\n * Stable identity, distinct from the `slug` address. Defaults to `slug`, and is\n * what every identity key (build id, interface ids) is built from.\n */\n readonly name: string\n /** Organization that owns the app — part of its build-id identity. */\n readonly organizationId: string\n readonly slug: string\n\n /** Views the app declares. */\n readonly views: NonNullable<DefineAppInput['views']>\n\n /** Background web workers the app declares. */\n readonly webWorkers: NonNullable<DefineAppInput['webWorkers']>\n\n /** Resolved app kind — `studio` or one of the SDK app types. */\n readonly applicationType?: string\n /** SDK app-view entrypoint, when declared. */\n readonly entry?: string\n /** Path to the app's icon SVG, resolved and shipped to Brett on deploy. */\n readonly icon?: string\n /** Dashboard visibility declared by the app; `undefined` when unset. */\n readonly visibility?: AppVisibility\n}\n\n/**\n * Resolve the workbench app for a CLI config, or `null` for a plain project or a\n * config (which is not an app — read it with `resolveWorkbenchConfig`).\n * @public\n */\nexport function resolveWorkbenchApp(\n cliConfig: CliConfig | null | undefined,\n): ResolvedWorkbenchApp | null {\n const app = cliConfig?.app\n // A config carries a distinct brand, so `isWorkbenchApp` is false for it — it\n // resolves to `null` here, like a plain project.\n if (!isWorkbenchApp(app)) return null\n\n const errors = validateWorkbenchApp(app)\n if (errors.length > 0) throw new Error(formatWorkbenchAppErrors(errors))\n\n return {\n applicationType: app.applicationType,\n entry: app.entry,\n icon: app.icon,\n // Identity defaults to the address, so existing apps behave identically.\n name: app.name ?? app.slug,\n organizationId: app.organizationId,\n slug: app.slug,\n views: app.views ?? [],\n visibility: app.visibility,\n webWorkers: app.webWorkers ?? [],\n }\n}\n"],"names":["isWorkbenchApp","formatWorkbenchAppErrors","validateWorkbenchApp","resolveWorkbenchApp","cliConfig","app","errors","length","Error","applicationType","entry","icon","name","slug","organizationId","views","visibility","webWorkers"],"mappings":"AAAA,gEAAgE;AAChE,8EAA8E;AAC9E,8EAA8E;AAC9E,gFAAgF;AAChF,0EAA0E;AAC1E,gEAAgE;AAKhE,SAA6BA,cAAc,QAAO,iBAAgB;AAClE,SAAQC,wBAAwB,EAAEC,oBAAoB,QAAO,4BAA2B;AAyCxF;;;;CAIC,GACD,OAAO,SAASC,oBACdC,SAAuC;IAEvC,MAAMC,MAAMD,WAAWC;IACvB,8EAA8E;IAC9E,iDAAiD;IACjD,IAAI,CAACL,eAAeK,MAAM,OAAO;IAEjC,MAAMC,SAASJ,qBAAqBG;IACpC,IAAIC,OAAOC,MAAM,GAAG,GAAG,MAAM,IAAIC,MAAMP,yBAAyBK;IAEhE,OAAO;QACLG,iBAAiBJ,IAAII,eAAe;QACpCC,OAAOL,IAAIK,KAAK;QAChBC,MAAMN,IAAIM,IAAI;QACd,yEAAyE;QACzEC,MAAMP,IAAIO,IAAI,IAAIP,IAAIQ,IAAI;QAC1BC,gBAAgBT,IAAIS,cAAc;QAClCD,MAAMR,IAAIQ,IAAI;QACdE,OAAOV,IAAIU,KAAK,IAAI,EAAE;QACtBC,YAAYX,IAAIW,UAAU;QAC1BC,YAAYZ,IAAIY,UAAU,IAAI,EAAE;IAClC;AACF"}
1
+ {"version":3,"sources":["../src/resolveWorkbenchApp.ts"],"sourcesContent":["// Package-internal shared resolver: turn a CLI config's branded\n// `defineApplication` app into its declared interfaces, or `null` for a plain\n// project — and for a config (a branded `unstable_defineMediaLibrary`), which\n// is not an app. The build and deploy accessors (actions/build, actions/deploy)\n// each build their command-specific view on top of this one brand-check +\n// extraction, so the discrimination lives in exactly one place.\n\nimport {type AppVisibility, type CliConfig} from '@sanity/cli-core'\n\nimport {type WorkbenchConfigValue} from './contract.js'\nimport {type DefineAppInput, isWorkbenchApp} from './defineApp.js'\nimport {formatWorkbenchAppErrors, validateWorkbenchApp} from './validateWorkbenchApp.js'\n\n/**\n * Bundled so adding a declaration family touches this type and the artifact\n * expanders, not every hop of build/dev plumbing in between. `config` is sourced\n * from `resolveWorkbenchConfig` (a config is not an app), not from this resolver.\n * @internal\n */\nexport interface WorkbenchExposes {\n config?: WorkbenchConfigValue\n views?: DefineAppInput['views']\n webWorkers?: DefineAppInput['webWorkers']\n}\n\n/** @public */\nexport interface ResolvedWorkbenchApp {\n /**\n * Stable identity, distinct from the `slug` address. Defaults to `slug`, and is\n * what every identity key (build id, interface ids) is built from.\n */\n readonly name: string\n /** Organization that owns the app — part of its build-id identity. */\n readonly organizationId: string\n readonly slug: string\n\n /** Views the app declares. */\n readonly views: NonNullable<DefineAppInput['views']>\n\n /** Background web workers the app declares. */\n readonly webWorkers: NonNullable<DefineAppInput['webWorkers']>\n\n /** Resolved app kind — `studio` or one of the SDK app types. */\n readonly applicationType?: string\n /** SDK app-view entrypoint, when declared. */\n readonly entry?: string\n /** Path to the app's icon SVG, resolved and shipped to Brett on deploy. */\n readonly icon?: string\n /** Explicit singleton flag for Sanity-owned apps. */\n readonly isSingleton?: boolean\n /** Dashboard visibility declared by the app; `undefined` when unset. */\n readonly visibility?: AppVisibility\n}\n\n/**\n * Resolve the workbench app for a CLI config, or `null` for a plain project or a\n * config (which is not an app — read it with `resolveWorkbenchConfig`).\n * @public\n */\nexport function resolveWorkbenchApp(\n cliConfig: CliConfig | null | undefined,\n): ResolvedWorkbenchApp | null {\n const app = cliConfig?.app\n // A config carries a distinct brand, so `isWorkbenchApp` is false for it — it\n // resolves to `null` here, like a plain project.\n if (!isWorkbenchApp(app)) return null\n\n const errors = validateWorkbenchApp(app)\n if (errors.length > 0) throw new Error(formatWorkbenchAppErrors(errors))\n\n return {\n applicationType: app.applicationType,\n entry: app.entry,\n icon: app.icon,\n ...(app.isSingleton === undefined ? {} : {isSingleton: app.isSingleton}),\n // Identity defaults to the address, so existing apps behave identically.\n name: app.name ?? app.slug,\n organizationId: app.organizationId,\n slug: app.slug,\n views: app.views ?? [],\n visibility: app.visibility,\n webWorkers: app.webWorkers ?? [],\n }\n}\n"],"names":["isWorkbenchApp","formatWorkbenchAppErrors","validateWorkbenchApp","resolveWorkbenchApp","cliConfig","app","errors","length","Error","applicationType","entry","icon","isSingleton","undefined","name","slug","organizationId","views","visibility","webWorkers"],"mappings":"AAAA,gEAAgE;AAChE,8EAA8E;AAC9E,8EAA8E;AAC9E,gFAAgF;AAChF,0EAA0E;AAC1E,gEAAgE;AAKhE,SAA6BA,cAAc,QAAO,iBAAgB;AAClE,SAAQC,wBAAwB,EAAEC,oBAAoB,QAAO,4BAA2B;AA2CxF;;;;CAIC,GACD,OAAO,SAASC,oBACdC,SAAuC;IAEvC,MAAMC,MAAMD,WAAWC;IACvB,8EAA8E;IAC9E,iDAAiD;IACjD,IAAI,CAACL,eAAeK,MAAM,OAAO;IAEjC,MAAMC,SAASJ,qBAAqBG;IACpC,IAAIC,OAAOC,MAAM,GAAG,GAAG,MAAM,IAAIC,MAAMP,yBAAyBK;IAEhE,OAAO;QACLG,iBAAiBJ,IAAII,eAAe;QACpCC,OAAOL,IAAIK,KAAK;QAChBC,MAAMN,IAAIM,IAAI;QACd,GAAIN,IAAIO,WAAW,KAAKC,YAAY,CAAC,IAAI;YAACD,aAAaP,IAAIO,WAAW;QAAA,CAAC;QACvE,yEAAyE;QACzEE,MAAMT,IAAIS,IAAI,IAAIT,IAAIU,IAAI;QAC1BC,gBAAgBX,IAAIW,cAAc;QAClCD,MAAMV,IAAIU,IAAI;QACdE,OAAOZ,IAAIY,KAAK,IAAI,EAAE;QACtBC,YAAYb,IAAIa,UAAU;QAC1BC,YAAYd,IAAIc,UAAU,IAAI,EAAE;IAClC;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/workbench-cli",
3
- "version": "2.2.2",
3
+ "version": "2.2.4",
4
4
  "description": "Internal implementation detail of the Sanity CLI's unstable workbench support. Not intended for direct use.",
5
5
  "homepage": "https://github.com/sanity-io/cli",
6
6
  "bugs": "https://github.com/sanity-io/cli/issues",
@@ -57,20 +57,20 @@
57
57
  "access": "public"
58
58
  },
59
59
  "dependencies": {
60
- "@module-federation/runtime": "2.8.2",
61
- "@module-federation/vite": "1.20.7",
60
+ "@module-federation/runtime": "2.9.0",
61
+ "@module-federation/vite": "1.21.0",
62
62
  "@sanity/types": "^6.7.0",
63
- "@vitejs/plugin-react": "^6.1.0",
63
+ "@vitejs/plugin-react": "^6.1.1",
64
64
  "form-data": "^4.0.5",
65
65
  "rxjs": "^7.8.2",
66
66
  "tar-fs": "^3.1.2",
67
- "vite": "^8.2.1",
67
+ "vite": "^8.2.2",
68
68
  "zod": "^4.4.3",
69
- "@sanity/cli-core": "^3.4.0"
69
+ "@sanity/cli-core": "^3.5.1"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@eslint/compat": "^2.1.0",
73
- "@sanity/pkg-utils": "^12.2.0",
73
+ "@sanity/pkg-utils": "^12.3.4",
74
74
  "@swc/cli": "^0.8.1",
75
75
  "@swc/core": "^1.15.43",
76
76
  "@types/node": "^22.20.0",
@@ -80,8 +80,8 @@
80
80
  "publint": "^0.3.21",
81
81
  "typescript": "^6.0.3",
82
82
  "vitest": "^4.1.11",
83
- "@repo/tsconfig": "3.70.0",
84
83
  "@repo/package.config": "0.0.1",
84
+ "@repo/tsconfig": "3.70.0",
85
85
  "@sanity/eslint-config-cli": "^1.1.3"
86
86
  },
87
87
  "engines": {