@sanity/workbench-cli 2.3.0 → 2.4.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 (36) hide show
  1. package/dist/_exports/build.d.ts +54 -2
  2. package/dist/_exports/build.js +1 -0
  3. package/dist/_exports/build.js.map +1 -1
  4. package/dist/_exports/{defineApp-BRFgHrPc.d.ts → defineApp-KCHd3Vab.d.ts} +25 -25
  5. package/dist/_exports/deploy.d.ts +3 -3
  6. package/dist/_exports/dev.d.ts +1 -1
  7. package/dist/_exports/index.d.ts +1 -1
  8. package/dist/_exports/init.d.ts +2 -2
  9. package/dist/_exports/preview.d.ts +1 -1
  10. package/dist/_exports/{registry-CexFxsKR.d.ts → registry-BCLMbrla.d.ts} +10 -10
  11. package/dist/_exports/{resolveWorkbenchConfig-CDUdRIjD.d.ts → resolveWorkbenchConfig-1CV651GT.d.ts} +2 -2
  12. package/dist/_exports/{summarizeInterfaces-BQ1v1O89.d.ts → summarizeInterfaces-DoG6OunM.d.ts} +3 -3
  13. package/dist/_exports/undeploy.d.ts +2 -2
  14. package/dist/actions/build/resource-bindings.js +56 -0
  15. package/dist/actions/build/resource-bindings.js.map +1 -0
  16. package/dist/actions/build/vite/plugin.js +6 -3
  17. package/dist/actions/build/vite/plugin.js.map +1 -1
  18. package/dist/actions/build/vite/plugins/plugin-sanity-environment.js +22 -3
  19. package/dist/actions/build/vite/plugins/plugin-sanity-environment.js.map +1 -1
  20. package/dist/actions/build/vite/plugins/plugin-sanity-federation-runtime.js +16 -4
  21. package/dist/actions/build/vite/plugins/plugin-sanity-federation-runtime.js.map +1 -1
  22. package/dist/actions/build/vite/workbench-vite-plugins.js +2 -1
  23. package/dist/actions/build/vite/workbench-vite-plugins.js.map +1 -1
  24. package/dist/actions/deploy/deployConfig.js +6 -6
  25. package/dist/actions/deploy/deployConfig.js.map +1 -1
  26. package/dist/actions/deploy/deployWorkbenchApp.js +6 -6
  27. package/dist/actions/deploy/deployWorkbenchApp.js.map +1 -1
  28. package/dist/actions/dev/startWorkbenchDevServer.js +3 -1
  29. package/dist/actions/dev/startWorkbenchDevServer.js.map +1 -1
  30. package/dist/actions/dev/toWireInterface.js +1 -1
  31. package/dist/actions/dev/toWireInterface.js.map +1 -1
  32. package/dist/actions/init/cliConfig.js +6 -6
  33. package/dist/actions/init/cliConfig.js.map +1 -1
  34. package/dist/contract.js +3 -3
  35. package/dist/contract.js.map +1 -1
  36. package/package.json +9 -10
@@ -1,5 +1,55 @@
1
- import { a as resolveWorkbenchApp, i as WorkbenchExposes, n as resolveWorkbenchConfig, r as ResolvedWorkbenchApp, t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-CDUdRIjD.js";
1
+ import { a as resolveWorkbenchApp, i as WorkbenchExposes, n as resolveWorkbenchConfig, r as ResolvedWorkbenchApp, t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-1CV651GT.js";
2
2
  import { PluginOption } from "vite";
3
+ /**
4
+ * Resource bindings ride in a dedicated module in the app's bundle rather than an
5
+ * index.html script tag, so both standalone studios and federated apps resolve
6
+ * them the same way (a federated host pulls modules, not HTML).
7
+ *
8
+ * The module is emitted at a stable, unhashed path (`sanity-resource-bindings.js`)
9
+ * at the bundle root and is statically imported first, so it is evaluated before
10
+ * any app code. At deploy time Brett replaces the `__SANITY_RESOURCE_BINDINGS__`
11
+ * token with the resolved bindings JSON. The token is invalid JSON on purpose: a
12
+ * minifier can't constant-fold `JSON.parse` of it, so the call — and the token —
13
+ * survive minification for Brett to rewrite.
14
+ *
15
+ * These constants are the single source of truth shared by the standalone studio
16
+ * build (`@sanity/cli-build`) and the federated app build here. They must stay in
17
+ * lockstep with Brett's replacement (see SDK-2413).
18
+ */
19
+ /** Rolldown chunk name used to force the bindings module into its own chunk. */
20
+ declare const RESOURCE_BINDINGS_CHUNK_NAME = "sanity-resource-bindings";
21
+ /** Stable, unhashed file name Brett looks for at the bundle root. */
22
+ declare const RESOURCE_BINDINGS_FILENAME = "sanity-resource-bindings.js";
23
+ /** Token Brett replaces with the resolved bindings JSON at deploy. */
24
+ declare const RESOURCE_BINDINGS_TOKEN = "__SANITY_RESOURCE_BINDINGS__";
25
+ /**
26
+ * Contents of the generated bindings module. The `JSON.parse` result is assigned
27
+ * to a global so the module has an observable side effect and isn't tree-shaken
28
+ * when nothing imports its export yet (the reader lands in SDK-2295). The
29
+ * try/catch keeps a local, un-deployed build (e.g. `sanity preview`) working: an
30
+ * unreplaced token throws, and we fall back to an empty array.
31
+ */
32
+ declare const RESOURCE_BINDINGS_MODULE_SOURCE = "// This file is auto-generated on 'sanity build' / 'sanity dev'\n// Modifications to this file are automatically discarded\nlet resourceBindings = []\ntry {\n resourceBindings = JSON.parse('__SANITY_RESOURCE_BINDINGS__')\n} catch {\n // Built but not deployed through Brett (e.g. local preview): keep the default.\n}\nglobalThis.__SANITY_RESOURCE_BINDINGS__ = resourceBindings\nexport {resourceBindings}\n";
33
+ /** Side-effect import placed first in each entry so the module evaluates before app code. */
34
+ declare const RESOURCE_BINDINGS_ENTRY_IMPORT = "import './sanity-resource-bindings.js'";
35
+ /**
36
+ * Rolldown `codeSplitting` group that isolates the bindings module into its own
37
+ * chunk. `minSize`/`minModuleSize` of 0 are scoped to this group (not the
38
+ * enclosing `codeSplitting` object) so they only affect the bindings module and
39
+ * never the automatic chunking of everything else. They stop Rolldown folding
40
+ * the tiny module back into its importer.
41
+ */
42
+ declare const resourceBindingsCodeSplittingGroup: {
43
+ minModuleSize: number;
44
+ minSize: number;
45
+ name: string;
46
+ test: RegExp;
47
+ };
48
+ /**
49
+ * `chunkFileNames` value for the bindings chunk (unhashed, at the bundle root),
50
+ * or `undefined` for any other chunk so the caller can apply its own default.
51
+ */
52
+ declare function resourceBindingsChunkFileName(chunkName: string): string | undefined;
3
53
  /**
4
54
  * Dep pre-bundling inputs for a workbench app's dev server.
5
55
  *
@@ -49,6 +99,8 @@ interface WorkbenchViteOptions {
49
99
  exposes?: WorkbenchExposes;
50
100
  /** App (vs studio) build — selects the discriminated federation option shape. */
51
101
  isApp?: boolean;
102
+ /** Blueprints build (via `@sanity/runtime-cli`) — emit the resource-bindings module. */
103
+ isBlueprints?: boolean;
52
104
  }
53
105
  /** Build the Vite plugins for a workbench app's module-federation remote. */
54
106
  declare function workbenchVitePlugins(options: WorkbenchViteOptions): Promise<PluginOption>;
@@ -59,5 +111,5 @@ declare function workbenchVitePlugins(options: WorkbenchViteOptions): Promise<Pl
59
111
  * its own id from the applications API.
60
112
  */
61
113
  declare function buildAppId(app: ResolvedWorkbenchApp): Promise<string>;
62
- export { type ResolvedMediaLibraryConfig, type WorkbenchExposes, buildAppId, resolveWorkbenchApp, resolveWorkbenchConfig, workbenchOptimizeDeps, workbenchVitePlugins };
114
+ export { RESOURCE_BINDINGS_CHUNK_NAME, RESOURCE_BINDINGS_ENTRY_IMPORT, RESOURCE_BINDINGS_FILENAME, RESOURCE_BINDINGS_MODULE_SOURCE, RESOURCE_BINDINGS_TOKEN, type ResolvedMediaLibraryConfig, type WorkbenchExposes, buildAppId, resolveWorkbenchApp, resolveWorkbenchConfig, resourceBindingsChunkFileName, resourceBindingsCodeSplittingGroup, workbenchOptimizeDeps, workbenchVitePlugins };
63
115
  //# sourceMappingURL=build.d.ts.map
@@ -3,6 +3,7 @@
3
3
  // resolver the build reads declared views/web workers 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 { RESOURCE_BINDINGS_CHUNK_NAME, RESOURCE_BINDINGS_ENTRY_IMPORT, RESOURCE_BINDINGS_FILENAME, RESOURCE_BINDINGS_MODULE_SOURCE, RESOURCE_BINDINGS_TOKEN, resourceBindingsChunkFileName, resourceBindingsCodeSplittingGroup } from '../actions/build/resource-bindings.js';
6
7
  export { workbenchOptimizeDeps } from '../actions/build/vite/optimize-deps.js';
7
8
  export { workbenchVitePlugins } from '../actions/build/vite/workbench-vite-plugins.js';
8
9
  export { buildAppId } from '../appId.js';
@@ -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/web workers 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 {buildAppId} from '../appId.js'\nexport {resolveWorkbenchApp, type WorkbenchExposes} from '../resolveWorkbenchApp.js'\nexport {type ResolvedMediaLibraryConfig, resolveWorkbenchConfig} from '../resolveWorkbenchConfig.js'\n"],"names":["workbenchOptimizeDeps","workbenchVitePlugins","buildAppId","resolveWorkbenchApp","resolveWorkbenchConfig"],"mappings":"AAAA,iEAAiE;AACjE,+EAA+E;AAC/E,+EAA+E;AAC/E,+EAA+E;AAC/E,sDAAsD;AAEtD,SAAQA,qBAAqB,QAAO,yCAAwC;AAC5E,SAAQC,oBAAoB,QAAO,kDAAiD;AACpF,SAAQC,UAAU,QAAO,cAAa;AACtC,SAAQC,mBAAmB,QAA8B,4BAA2B;AACpF,SAAyCC,sBAAsB,QAAO,+BAA8B"}
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/web workers 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 {\n RESOURCE_BINDINGS_CHUNK_NAME,\n RESOURCE_BINDINGS_ENTRY_IMPORT,\n RESOURCE_BINDINGS_FILENAME,\n RESOURCE_BINDINGS_MODULE_SOURCE,\n RESOURCE_BINDINGS_TOKEN,\n resourceBindingsChunkFileName,\n resourceBindingsCodeSplittingGroup,\n} from '../actions/build/resource-bindings.js'\nexport {workbenchOptimizeDeps} from '../actions/build/vite/optimize-deps.js'\nexport {workbenchVitePlugins} from '../actions/build/vite/workbench-vite-plugins.js'\nexport {buildAppId} from '../appId.js'\nexport {resolveWorkbenchApp, type WorkbenchExposes} from '../resolveWorkbenchApp.js'\nexport {type ResolvedMediaLibraryConfig, resolveWorkbenchConfig} from '../resolveWorkbenchConfig.js'\n"],"names":["RESOURCE_BINDINGS_CHUNK_NAME","RESOURCE_BINDINGS_ENTRY_IMPORT","RESOURCE_BINDINGS_FILENAME","RESOURCE_BINDINGS_MODULE_SOURCE","RESOURCE_BINDINGS_TOKEN","resourceBindingsChunkFileName","resourceBindingsCodeSplittingGroup","workbenchOptimizeDeps","workbenchVitePlugins","buildAppId","resolveWorkbenchApp","resolveWorkbenchConfig"],"mappings":"AAAA,iEAAiE;AACjE,+EAA+E;AAC/E,+EAA+E;AAC/E,+EAA+E;AAC/E,sDAAsD;AAEtD,SACEA,4BAA4B,EAC5BC,8BAA8B,EAC9BC,0BAA0B,EAC1BC,+BAA+B,EAC/BC,uBAAuB,EACvBC,6BAA6B,EAC7BC,kCAAkC,QAC7B,wCAAuC;AAC9C,SAAQC,qBAAqB,QAAO,yCAAwC;AAC5E,SAAQC,oBAAoB,QAAO,kDAAiD;AACpF,SAAQC,UAAU,QAAO,cAAa;AACtC,SAAQC,mBAAmB,QAA8B,4BAA2B;AACpF,SAAyCC,sBAAsB,QAAO,+BAA8B"}
@@ -39,18 +39,18 @@ type TileSize = z.infer<typeof TileSizeSchema>;
39
39
  /** @public */
40
40
  type ServiceType = 'worker';
41
41
  declare const DockGroupSchema: z.ZodMiniEnum<{
42
- "dock.system": "dock.system";
43
- "dock.applications": "dock.applications";
44
- "dock.user": "dock.user";
42
+ system: "system";
43
+ applications: "applications";
44
+ user: "user";
45
45
  }>;
46
46
  /** @public */
47
47
  type DockGroup = z.output<typeof DockGroupSchema>;
48
48
  declare const PanelViewSchema: z.ZodMiniObject<{
49
49
  dock: z.ZodMiniOptional<z.ZodMiniObject<{
50
50
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
51
- "dock.system": "dock.system";
52
- "dock.applications": "dock.applications";
53
- "dock.user": "dock.user";
51
+ system: "system";
52
+ applications: "applications";
53
+ user: "user";
54
54
  }>>;
55
55
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
56
56
  }, z.core.$strip>>;
@@ -68,9 +68,9 @@ declare function definePanelView(view: DefinePanelViewInput): PanelView;
68
68
  declare const WindowViewSchema: z.ZodMiniObject<{
69
69
  dock: z.ZodMiniOptional<z.ZodMiniObject<{
70
70
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
71
- "dock.system": "dock.system";
72
- "dock.applications": "dock.applications";
73
- "dock.user": "dock.user";
71
+ system: "system";
72
+ applications: "applications";
73
+ user: "user";
74
74
  }>>;
75
75
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
76
76
  }, z.core.$strip>>;
@@ -119,9 +119,9 @@ declare function defineTileView(view: DefineTileViewInput): TileView;
119
119
  declare const InterfaceDeclarationSchema: z.ZodMiniDiscriminatedUnion<[z.ZodMiniObject<{
120
120
  dock: z.ZodMiniOptional<z.ZodMiniObject<{
121
121
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
122
- "dock.system": "dock.system";
123
- "dock.applications": "dock.applications";
124
- "dock.user": "dock.user";
122
+ system: "system";
123
+ applications: "applications";
124
+ user: "user";
125
125
  }>>;
126
126
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
127
127
  }, z.core.$strip>>;
@@ -132,9 +132,9 @@ declare const InterfaceDeclarationSchema: z.ZodMiniDiscriminatedUnion<[z.ZodMini
132
132
  }, z.core.$strip>, z.ZodMiniObject<{
133
133
  dock: z.ZodMiniOptional<z.ZodMiniObject<{
134
134
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
135
- "dock.system": "dock.system";
136
- "dock.applications": "dock.applications";
137
- "dock.user": "dock.user";
135
+ system: "system";
136
+ applications: "applications";
137
+ user: "user";
138
138
  }>>;
139
139
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
140
140
  }, z.core.$strip>>;
@@ -206,9 +206,9 @@ declare const DefineAppInputSchema: z.ZodMiniObject<{
206
206
  }>>;
207
207
  dock: z.ZodMiniOptional<z.ZodMiniObject<{
208
208
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
209
- "dock.system": "dock.system";
210
- "dock.applications": "dock.applications";
211
- "dock.user": "dock.user";
209
+ system: "system";
210
+ applications: "applications";
211
+ user: "user";
212
212
  }>>;
213
213
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
214
214
  }, z.core.$strip>>;
@@ -222,9 +222,9 @@ declare const DefineAppInputSchema: z.ZodMiniObject<{
222
222
  views: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniDiscriminatedUnion<[z.ZodMiniObject<{
223
223
  dock: z.ZodMiniOptional<z.ZodMiniObject<{
224
224
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
225
- "dock.system": "dock.system";
226
- "dock.applications": "dock.applications";
227
- "dock.user": "dock.user";
225
+ system: "system";
226
+ applications: "applications";
227
+ user: "user";
228
228
  }>>;
229
229
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
230
230
  }, z.core.$strip>>;
@@ -235,9 +235,9 @@ declare const DefineAppInputSchema: z.ZodMiniObject<{
235
235
  }, z.core.$strip>, z.ZodMiniObject<{
236
236
  dock: z.ZodMiniOptional<z.ZodMiniObject<{
237
237
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
238
- "dock.system": "dock.system";
239
- "dock.applications": "dock.applications";
240
- "dock.user": "dock.user";
238
+ system: "system";
239
+ applications: "applications";
240
+ user: "user";
241
241
  }>>;
242
242
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
243
243
  }, z.core.$strip>>;
@@ -373,4 +373,4 @@ declare function isWorkbenchConfig(app: unknown): app is WorkbenchConfig;
373
373
  */
374
374
  declare function unstable_defineMediaLibrary(input: DefineMediaLibraryInput): WorkbenchConfig;
375
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 };
376
- //# sourceMappingURL=defineApp-BRFgHrPc.d.ts.map
376
+ //# sourceMappingURL=defineApp-KCHd3Vab.d.ts.map
@@ -1,6 +1,6 @@
1
- import "./defineApp-BRFgHrPc.js";
2
- import { n as resolveWorkbenchConfig, t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-CDUdRIjD.js";
3
- import { a as DeployableWorkbenchApp, i as summarizeInterfaces, n as DeployedView, o as getWorkbench, r as DeployedWebWorker, t as DeployedInterface } from "./summarizeInterfaces-BQ1v1O89.js";
1
+ import "./defineApp-KCHd3Vab.js";
2
+ import { n as resolveWorkbenchConfig, t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-1CV651GT.js";
3
+ import { a as DeployableWorkbenchApp, i as summarizeInterfaces, n as DeployedView, o as getWorkbench, r as DeployedWebWorker, t as DeployedInterface } from "./summarizeInterfaces-DoG6OunM.js";
4
4
  import { AppVisibility, CliConfig, Output } from "@sanity/cli-core";
5
5
  import "node:zlib";
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { t as DevServerManifest } from "./registry-CexFxsKR.js";
1
+ import { t as DevServerManifest } from "./registry-BCLMbrla.js";
2
2
  import { CliConfig, Output } from "@sanity/cli-core";
3
3
  import { ViteDevServer } from "vite";
4
4
  /**
@@ -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-BRFgHrPc.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-KCHd3Vab.js";
2
2
  import { AssetSourceComponentProps } from "@sanity/types";
3
3
  /**
4
4
  * The service's own declaration, surfaced to the callback.
@@ -1,10 +1,10 @@
1
1
  /** App scaffold — `entry` auto-declares the navigable app view. */
2
- declare const workbenchAppConfigTemplate = "\nimport {defineCliConfig, unstable_defineApp} from 'sanity/cli'\n\nexport default defineCliConfig({\n app: unstable_defineApp({\n title: '%title%',\n slug: '%slug%',\n organizationId: '%organizationId%',\n entry: '%entry%',\n }),\n})\n";
2
+ declare const workbenchAppConfigTemplate = "\nimport {defineApplication, defineCliConfig} from 'sanity/cli'\n\nexport default defineCliConfig({\n app: defineApplication({\n title: '%title%',\n slug: '%slug%',\n organizationId: '%organizationId%',\n entry: '%entry%',\n }),\n})\n";
3
3
  /**
4
4
  * Studio scaffold — brands with slug/title only, no `entry` (studio app views
5
5
  * aren't implemented yet).
6
6
  */
7
- declare const workbenchStudioConfigTemplate = "\nimport {defineCliConfig, unstable_defineApp} from 'sanity/cli'\n\nexport default defineCliConfig({\n api: {\n projectId: '%projectId%',\n dataset: '%dataset%'\n },\n app: unstable_defineApp({\n title: '%title%',\n slug: '%slug%',\n organizationId: '%organizationId%',\n }),\n deployment: {\n /**\n * Enable auto-updates for studios.\n * Learn more at https://www.sanity.io/docs/studio/latest-version-of-sanity#k47faf43faf56\n */\n autoUpdates: __BOOL__autoUpdates__,\n },\n})\n";
7
+ declare const workbenchStudioConfigTemplate = "\nimport {defineApplication, defineCliConfig} from 'sanity/cli'\n\nexport default defineCliConfig({\n api: {\n projectId: '%projectId%',\n dataset: '%dataset%'\n },\n app: defineApplication({\n title: '%title%',\n slug: '%slug%',\n organizationId: '%organizationId%',\n }),\n deployment: {\n /**\n * Enable auto-updates for studios.\n * Learn more at https://www.sanity.io/docs/studio/latest-version-of-sanity#k47faf43faf56\n */\n autoUpdates: __BOOL__autoUpdates__,\n },\n})\n";
8
8
  declare function toAppSlug(value: string): string | null;
9
9
  export { toAppSlug, workbenchAppConfigTemplate, workbenchStudioConfigTemplate };
10
10
  //# sourceMappingURL=init.d.ts.map
@@ -1,4 +1,4 @@
1
- import { t as DevServerManifest } from "./registry-CexFxsKR.js";
1
+ import { t as DevServerManifest } from "./registry-BCLMbrla.js";
2
2
  import { CliConfig, Output } from "@sanity/cli-core";
3
3
  interface StartWorkbenchPreviewOptions {
4
4
  /** Directory for the workbench Vite server's dependency cache. */
@@ -18,9 +18,9 @@ declare const devServerManifestSchema: z.ZodMiniObject<{
18
18
  metadata: z.ZodMiniNullable<z.ZodMiniObject<{
19
19
  dock: z.ZodMiniObject<{
20
20
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
21
- "dock.system": "dock.system";
22
- "dock.applications": "dock.applications";
23
- "dock.user": "dock.user";
21
+ system: "system";
22
+ applications: "applications";
23
+ user: "user";
24
24
  }>>;
25
25
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
26
26
  }, z.core.$strip>;
@@ -36,9 +36,9 @@ declare const devServerManifestSchema: z.ZodMiniObject<{
36
36
  metadata: z.ZodMiniNullable<z.ZodMiniObject<{
37
37
  dock: z.ZodMiniObject<{
38
38
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
39
- "dock.system": "dock.system";
40
- "dock.applications": "dock.applications";
41
- "dock.user": "dock.user";
39
+ system: "system";
40
+ applications: "applications";
41
+ user: "user";
42
42
  }>>;
43
43
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
44
44
  }, z.core.$strip>;
@@ -88,9 +88,9 @@ declare const devServerManifestSchema: z.ZodMiniObject<{
88
88
  manifest: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnknown>, z.ZodMiniObject<{
89
89
  dock: z.ZodMiniOptional<z.ZodMiniObject<{
90
90
  group: z.ZodMiniOptional<z.ZodMiniEnum<{
91
- "dock.system": "dock.system";
92
- "dock.applications": "dock.applications";
93
- "dock.user": "dock.user";
91
+ system: "system";
92
+ applications: "applications";
93
+ user: "user";
94
94
  }>>;
95
95
  order: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
96
96
  }, z.core.$strip>>;
@@ -122,4 +122,4 @@ declare const devServerManifestSchema: z.ZodMiniObject<{
122
122
  */
123
123
  type DevServerManifest = z.infer<typeof devServerManifestSchema>;
124
124
  export { DevServerManifest as t };
125
- //# sourceMappingURL=registry-CexFxsKR.d.ts.map
125
+ //# sourceMappingURL=registry-BCLMbrla.d.ts.map
@@ -1,4 +1,4 @@
1
- import { A as WorkbenchConfigValue, t as DefineAppInput } from "./defineApp-BRFgHrPc.js";
1
+ import { A as WorkbenchConfigValue, t as DefineAppInput } from "./defineApp-KCHd3Vab.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
@@ -59,4 +59,4 @@ interface ResolvedMediaLibraryConfig {
59
59
  */
60
60
  declare function resolveWorkbenchConfig(cliConfig: CliConfig | null | undefined): ResolvedMediaLibraryConfig | null;
61
61
  export { resolveWorkbenchApp as a, WorkbenchExposes as i, resolveWorkbenchConfig as n, ResolvedWorkbenchApp as r, ResolvedMediaLibraryConfig as t };
62
- //# sourceMappingURL=resolveWorkbenchConfig-CDUdRIjD.d.ts.map
62
+ //# sourceMappingURL=resolveWorkbenchConfig-1CV651GT.d.ts.map
@@ -1,5 +1,5 @@
1
- import { D as ViewSurface, b as ServiceType } from "./defineApp-BRFgHrPc.js";
2
- import { i as WorkbenchExposes, r as ResolvedWorkbenchApp } from "./resolveWorkbenchConfig-CDUdRIjD.js";
1
+ import { D as ViewSurface, b as ServiceType } from "./defineApp-KCHd3Vab.js";
2
+ import { i as WorkbenchExposes, r as ResolvedWorkbenchApp } from "./resolveWorkbenchConfig-1CV651GT.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-BQ1v1O89.d.ts.map
65
+ //# sourceMappingURL=summarizeInterfaces-DoG6OunM.d.ts.map
@@ -1,5 +1,5 @@
1
- import { t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-CDUdRIjD.js";
2
- import { a as DeployableWorkbenchApp, n as DeployedView, r as DeployedWebWorker } from "./summarizeInterfaces-BQ1v1O89.js";
1
+ import { t as ResolvedMediaLibraryConfig } from "./resolveWorkbenchConfig-1CV651GT.js";
2
+ import { a as DeployableWorkbenchApp, n as DeployedView, r as DeployedWebWorker } from "./summarizeInterfaces-DoG6OunM.js";
3
3
  import "node:zlib";
4
4
  import { UndeployAdapter, UndeployApplicationTarget, UndeployConfigTarget } from "@sanity/cli-core/undeploy";
5
5
  interface ConfigSnapshot {
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Resource bindings ride in a dedicated module in the app's bundle rather than an
3
+ * index.html script tag, so both standalone studios and federated apps resolve
4
+ * them the same way (a federated host pulls modules, not HTML).
5
+ *
6
+ * The module is emitted at a stable, unhashed path (`sanity-resource-bindings.js`)
7
+ * at the bundle root and is statically imported first, so it is evaluated before
8
+ * any app code. At deploy time Brett replaces the `__SANITY_RESOURCE_BINDINGS__`
9
+ * token with the resolved bindings JSON. The token is invalid JSON on purpose: a
10
+ * minifier can't constant-fold `JSON.parse` of it, so the call — and the token —
11
+ * survive minification for Brett to rewrite.
12
+ *
13
+ * These constants are the single source of truth shared by the standalone studio
14
+ * build (`@sanity/cli-build`) and the federated app build here. They must stay in
15
+ * lockstep with Brett's replacement (see SDK-2413).
16
+ */ /** Rolldown chunk name used to force the bindings module into its own chunk. */ export const RESOURCE_BINDINGS_CHUNK_NAME = 'sanity-resource-bindings';
17
+ /** Stable, unhashed file name Brett looks for at the bundle root. */ export const RESOURCE_BINDINGS_FILENAME = `${RESOURCE_BINDINGS_CHUNK_NAME}.js`;
18
+ /** Token Brett replaces with the resolved bindings JSON at deploy. */ export const RESOURCE_BINDINGS_TOKEN = '__SANITY_RESOURCE_BINDINGS__';
19
+ /**
20
+ * Contents of the generated bindings module. The `JSON.parse` result is assigned
21
+ * to a global so the module has an observable side effect and isn't tree-shaken
22
+ * when nothing imports its export yet (the reader lands in SDK-2295). The
23
+ * try/catch keeps a local, un-deployed build (e.g. `sanity preview`) working: an
24
+ * unreplaced token throws, and we fall back to an empty array.
25
+ */ export const RESOURCE_BINDINGS_MODULE_SOURCE = `// This file is auto-generated on 'sanity build' / 'sanity dev'
26
+ // Modifications to this file are automatically discarded
27
+ let resourceBindings = []
28
+ try {
29
+ resourceBindings = JSON.parse('${RESOURCE_BINDINGS_TOKEN}')
30
+ } catch {
31
+ // Built but not deployed through Brett (e.g. local preview): keep the default.
32
+ }
33
+ globalThis.${RESOURCE_BINDINGS_TOKEN} = resourceBindings
34
+ export {resourceBindings}
35
+ `;
36
+ /** Side-effect import placed first in each entry so the module evaluates before app code. */ export const RESOURCE_BINDINGS_ENTRY_IMPORT = `import './${RESOURCE_BINDINGS_FILENAME}'`;
37
+ /**
38
+ * Rolldown `codeSplitting` group that isolates the bindings module into its own
39
+ * chunk. `minSize`/`minModuleSize` of 0 are scoped to this group (not the
40
+ * enclosing `codeSplitting` object) so they only affect the bindings module and
41
+ * never the automatic chunking of everything else. They stop Rolldown folding
42
+ * the tiny module back into its importer.
43
+ */ export const resourceBindingsCodeSplittingGroup = {
44
+ minModuleSize: 0,
45
+ minSize: 0,
46
+ name: RESOURCE_BINDINGS_CHUNK_NAME,
47
+ test: new RegExp(RESOURCE_BINDINGS_CHUNK_NAME)
48
+ };
49
+ /**
50
+ * `chunkFileNames` value for the bindings chunk (unhashed, at the bundle root),
51
+ * or `undefined` for any other chunk so the caller can apply its own default.
52
+ */ export function resourceBindingsChunkFileName(chunkName) {
53
+ return chunkName === RESOURCE_BINDINGS_CHUNK_NAME ? RESOURCE_BINDINGS_FILENAME : undefined;
54
+ }
55
+
56
+ //# sourceMappingURL=resource-bindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/build/resource-bindings.ts"],"sourcesContent":["/**\n * Resource bindings ride in a dedicated module in the app's bundle rather than an\n * index.html script tag, so both standalone studios and federated apps resolve\n * them the same way (a federated host pulls modules, not HTML).\n *\n * The module is emitted at a stable, unhashed path (`sanity-resource-bindings.js`)\n * at the bundle root and is statically imported first, so it is evaluated before\n * any app code. At deploy time Brett replaces the `__SANITY_RESOURCE_BINDINGS__`\n * token with the resolved bindings JSON. The token is invalid JSON on purpose: a\n * minifier can't constant-fold `JSON.parse` of it, so the call — and the token —\n * survive minification for Brett to rewrite.\n *\n * These constants are the single source of truth shared by the standalone studio\n * build (`@sanity/cli-build`) and the federated app build here. They must stay in\n * lockstep with Brett's replacement (see SDK-2413).\n */\n\n/** Rolldown chunk name used to force the bindings module into its own chunk. */\nexport const RESOURCE_BINDINGS_CHUNK_NAME = 'sanity-resource-bindings'\n\n/** Stable, unhashed file name Brett looks for at the bundle root. */\nexport const RESOURCE_BINDINGS_FILENAME = `${RESOURCE_BINDINGS_CHUNK_NAME}.js`\n\n/** Token Brett replaces with the resolved bindings JSON at deploy. */\nexport const RESOURCE_BINDINGS_TOKEN = '__SANITY_RESOURCE_BINDINGS__'\n\n/**\n * Contents of the generated bindings module. The `JSON.parse` result is assigned\n * to a global so the module has an observable side effect and isn't tree-shaken\n * when nothing imports its export yet (the reader lands in SDK-2295). The\n * try/catch keeps a local, un-deployed build (e.g. `sanity preview`) working: an\n * unreplaced token throws, and we fall back to an empty array.\n */\nexport const RESOURCE_BINDINGS_MODULE_SOURCE = `// This file is auto-generated on 'sanity build' / 'sanity dev'\n// Modifications to this file are automatically discarded\nlet resourceBindings = []\ntry {\n resourceBindings = JSON.parse('${RESOURCE_BINDINGS_TOKEN}')\n} catch {\n // Built but not deployed through Brett (e.g. local preview): keep the default.\n}\nglobalThis.${RESOURCE_BINDINGS_TOKEN} = resourceBindings\nexport {resourceBindings}\n`\n\n/** Side-effect import placed first in each entry so the module evaluates before app code. */\nexport const RESOURCE_BINDINGS_ENTRY_IMPORT = `import './${RESOURCE_BINDINGS_FILENAME}'`\n\n/**\n * Rolldown `codeSplitting` group that isolates the bindings module into its own\n * chunk. `minSize`/`minModuleSize` of 0 are scoped to this group (not the\n * enclosing `codeSplitting` object) so they only affect the bindings module and\n * never the automatic chunking of everything else. They stop Rolldown folding\n * the tiny module back into its importer.\n */\nexport const resourceBindingsCodeSplittingGroup = {\n minModuleSize: 0,\n minSize: 0,\n name: RESOURCE_BINDINGS_CHUNK_NAME,\n test: new RegExp(RESOURCE_BINDINGS_CHUNK_NAME),\n}\n\n/**\n * `chunkFileNames` value for the bindings chunk (unhashed, at the bundle root),\n * or `undefined` for any other chunk so the caller can apply its own default.\n */\nexport function resourceBindingsChunkFileName(chunkName: string): string | undefined {\n return chunkName === RESOURCE_BINDINGS_CHUNK_NAME ? RESOURCE_BINDINGS_FILENAME : undefined\n}\n"],"names":["RESOURCE_BINDINGS_CHUNK_NAME","RESOURCE_BINDINGS_FILENAME","RESOURCE_BINDINGS_TOKEN","RESOURCE_BINDINGS_MODULE_SOURCE","RESOURCE_BINDINGS_ENTRY_IMPORT","resourceBindingsCodeSplittingGroup","minModuleSize","minSize","name","test","RegExp","resourceBindingsChunkFileName","chunkName","undefined"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,8EAA8E,GAC9E,OAAO,MAAMA,+BAA+B,2BAA0B;AAEtE,mEAAmE,GACnE,OAAO,MAAMC,6BAA6B,GAAGD,6BAA6B,GAAG,CAAC,CAAA;AAE9E,oEAAoE,GACpE,OAAO,MAAME,0BAA0B,+BAA8B;AAErE;;;;;;CAMC,GACD,OAAO,MAAMC,kCAAkC,CAAC;;;;iCAIf,EAAED,wBAAwB;;;;WAIhD,EAAEA,wBAAwB;;AAErC,CAAC,CAAA;AAED,2FAA2F,GAC3F,OAAO,MAAME,iCAAiC,CAAC,UAAU,EAAEH,2BAA2B,CAAC,CAAC,CAAA;AAExF;;;;;;CAMC,GACD,OAAO,MAAMI,qCAAqC;IAChDC,eAAe;IACfC,SAAS;IACTC,MAAMR;IACNS,MAAM,IAAIC,OAAOV;AACnB,EAAC;AAED;;;CAGC,GACD,OAAO,SAASW,8BAA8BC,SAAiB;IAC7D,OAAOA,cAAcZ,+BAA+BC,6BAA6BY;AACnF"}
@@ -8,7 +8,7 @@ import { sanityFederationRuntime } from './plugins/plugin-sanity-federation-runt
8
8
  /**
9
9
  * @internal
10
10
  */ export const federation = (options)=>{
11
- const { exposes, name: defaultName, pkgJson, workDir = process.cwd() } = options;
11
+ const { exposes, isBlueprints, name: defaultName, pkgJson, workDir = process.cwd() } = options;
12
12
  let name = defaultName;
13
13
  if (!name) {
14
14
  name = pkgJson?.name;
@@ -43,9 +43,11 @@ import { sanityFederationRuntime } from './plugins/plugin-sanity-federation-runt
43
43
  };
44
44
  const runtimeOptions = options.isApp ? {
45
45
  appEntry: options.appEntry,
46
- isApp: true
46
+ isApp: true,
47
+ isBlueprints
47
48
  } : {
48
49
  isApp: false,
50
+ isBlueprints,
49
51
  studioConfigPath: options.studioConfigPath
50
52
  };
51
53
  // Every federated app and studio also serves itself standalone. Whenever there's
@@ -55,7 +57,8 @@ import { sanityFederationRuntime } from './plugins/plugin-sanity-federation-runt
55
57
  return [
56
58
  sanityEnvironmentPlugin({
57
59
  clientInput,
58
- input: entryPath
60
+ input: entryPath,
61
+ isBlueprints
59
62
  }),
60
63
  sanityFederationRuntime(runtimeOptions),
61
64
  sanityExtensionArtifacts({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/actions/build/vite/plugin.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {type ModuleFederationOptions} from '@module-federation/vite'\nimport {type PackageJson} from '@sanity/cli-core'\nimport {type PluginOption} from 'vite'\n\nimport {type WorkbenchExposes} from '../../../resolveWorkbenchApp.js'\nimport {artifactExposes, workbenchArtifacts} from '../artifact.js'\nimport {FEDERATION_FILE_NAME, RUNTIME_DIR} from './constants.js'\nimport {type FederationOptions, sanityModuleFederation} from './plugins/plugin-module-federation.js'\nimport {sanityEnvironmentPlugin} from './plugins/plugin-sanity-environment.js'\nimport {sanityExtensionArtifacts} from './plugins/plugin-sanity-extension-artifacts.js'\nimport {\n type FederationRuntimeOptions,\n sanityFederationRuntime,\n} from './plugins/plugin-sanity-federation-runtime.js'\n\ninterface FederationPluginOptionsBase extends Omit<Partial<FederationOptions>, 'exposes'> {\n exposes?: WorkbenchExposes\n pkgJson?: PackageJson\n /**\n * Current working directory to read package.json from, defaults to process.cwd()\n */\n workDir?: string\n}\n\ninterface AppFederationPluginOptions extends FederationPluginOptionsBase {\n isApp: true\n\n /**\n * Relative path to the App entry from the runtime directory, e.g.\n * `../../src/App.tsx`. Omit it for a dock-only app that declares no `entry`:\n * no `./App` is exposed and the remote serves only its views.\n */\n appEntry?: string\n studioConfigPath?: never\n}\n\ninterface StudioFederationPluginOptions extends FederationPluginOptionsBase {\n /** relative path to the Studio config file from the runtime directory (e.g. `../../sanity.config.ts`). */\n studioConfigPath: string\n\n appEntry?: never\n /** @defaultValue false */\n isApp?: false\n}\n\n/**\n * Plugin options for the federation vite plugin.\n *\n * Discriminated on `isApp`:\n * - `isApp: true` → requires `appEntry`\n * - `isApp: false` (default) → requires `studioConfigPath`\n *\n * @internal\n */\ntype FederationPluginOptions = AppFederationPluginOptions | StudioFederationPluginOptions\n\n/**\n * @internal\n */\nexport const federation = (options: FederationPluginOptions): PluginOption => {\n const {exposes, name: defaultName, pkgJson, workDir = process.cwd()} = options\n\n let name = defaultName\n\n if (!name) {\n name = pkgJson?.name\n }\n\n if (!name) {\n throw new Error('\"name\" option is required but could not be inferred from package.json')\n }\n\n const generatedEntry = `./${RUNTIME_DIR}/${FEDERATION_FILE_NAME}.jsx`\n\n function resolveEntryPath(entry: string) {\n const resolvedPath = path.resolve(workDir, entry)\n\n if (!resolvedPath) {\n throw new Error(\n `Could not resolve path for entry \"${entry}\". Please check that the file exists and the path is correct.`,\n )\n }\n\n return resolvedPath\n }\n\n const entryPath = resolveEntryPath(generatedEntry)\n\n // Each view component (`./views/<view>/<component>`) and each service loader\n // (`./services/<name>`) is exposed straight to the host, pointing at the file\n // the extension-artifacts plugin generates under RUNTIME_DIR. A service's\n // worker bundle carries no expose — the host reaches it through its loader.\n const artifacts = workbenchArtifacts(exposes ?? {})\n const artifactModuleExposes = artifactExposes(artifacts, (artifactPath) =>\n resolveEntryPath(`./${RUNTIME_DIR}/${artifactPath}`),\n )\n\n // A dock-only app (`isApp` with no `appEntry`) has no navigable full-page\n // view, so it exposes no `./App` — only its views. Studios and apps with an\n // entry expose `./App` (the generated render entry).\n const exposesApp = !options.isApp || options.appEntry !== undefined\n\n const federationExposes: NonNullable<ModuleFederationOptions['exposes']> = {\n ...(exposesApp ? {'./App': entryPath} : {}),\n ...artifactModuleExposes,\n }\n\n const runtimeOptions: FederationRuntimeOptions = options.isApp\n ? {appEntry: options.appEntry, isApp: true}\n : {isApp: false, studioConfigPath: options.studioConfigPath}\n\n // Every federated app and studio also serves itself standalone. Whenever there's\n // an `./App` to mount (never for a dock-only app), build the SPA client\n // environment from the runtime bootstrap cli-build writes.\n const clientInput = exposesApp ? path.join(workDir, '.sanity', 'runtime', 'app.js') : undefined\n\n return [\n sanityEnvironmentPlugin({clientInput, input: entryPath}),\n sanityFederationRuntime(runtimeOptions),\n sanityExtensionArtifacts({artifacts}),\n sanityModuleFederation({exposes: federationExposes, name}),\n ]\n}\n"],"names":["path","artifactExposes","workbenchArtifacts","FEDERATION_FILE_NAME","RUNTIME_DIR","sanityModuleFederation","sanityEnvironmentPlugin","sanityExtensionArtifacts","sanityFederationRuntime","federation","options","exposes","name","defaultName","pkgJson","workDir","process","cwd","Error","generatedEntry","resolveEntryPath","entry","resolvedPath","resolve","entryPath","artifacts","artifactModuleExposes","artifactPath","exposesApp","isApp","appEntry","undefined","federationExposes","runtimeOptions","studioConfigPath","clientInput","join","input"],"mappings":"AAAA,OAAOA,UAAU,YAAW;AAO5B,SAAQC,eAAe,EAAEC,kBAAkB,QAAO,iBAAgB;AAClE,SAAQC,oBAAoB,EAAEC,WAAW,QAAO,iBAAgB;AAChE,SAAgCC,sBAAsB,QAAO,wCAAuC;AACpG,SAAQC,uBAAuB,QAAO,yCAAwC;AAC9E,SAAQC,wBAAwB,QAAO,iDAAgD;AACvF,SAEEC,uBAAuB,QAClB,gDAA+C;AA2CtD;;CAEC,GACD,OAAO,MAAMC,aAAa,CAACC;IACzB,MAAM,EAACC,OAAO,EAAEC,MAAMC,WAAW,EAAEC,OAAO,EAAEC,UAAUC,QAAQC,GAAG,EAAE,EAAC,GAAGP;IAEvE,IAAIE,OAAOC;IAEX,IAAI,CAACD,MAAM;QACTA,OAAOE,SAASF;IAClB;IAEA,IAAI,CAACA,MAAM;QACT,MAAM,IAAIM,MAAM;IAClB;IAEA,MAAMC,iBAAiB,CAAC,EAAE,EAAEf,YAAY,CAAC,EAAED,qBAAqB,IAAI,CAAC;IAErE,SAASiB,iBAAiBC,KAAa;QACrC,MAAMC,eAAetB,KAAKuB,OAAO,CAACR,SAASM;QAE3C,IAAI,CAACC,cAAc;YACjB,MAAM,IAAIJ,MACR,CAAC,kCAAkC,EAAEG,MAAM,6DAA6D,CAAC;QAE7G;QAEA,OAAOC;IACT;IAEA,MAAME,YAAYJ,iBAAiBD;IAEnC,6EAA6E;IAC7E,8EAA8E;IAC9E,0EAA0E;IAC1E,4EAA4E;IAC5E,MAAMM,YAAYvB,mBAAmBS,WAAW,CAAC;IACjD,MAAMe,wBAAwBzB,gBAAgBwB,WAAW,CAACE,eACxDP,iBAAiB,CAAC,EAAE,EAAEhB,YAAY,CAAC,EAAEuB,cAAc;IAGrD,0EAA0E;IAC1E,4EAA4E;IAC5E,qDAAqD;IACrD,MAAMC,aAAa,CAAClB,QAAQmB,KAAK,IAAInB,QAAQoB,QAAQ,KAAKC;IAE1D,MAAMC,oBAAqE;QACzE,GAAIJ,aAAa;YAAC,SAASJ;QAAS,IAAI,CAAC,CAAC;QAC1C,GAAGE,qBAAqB;IAC1B;IAEA,MAAMO,iBAA2CvB,QAAQmB,KAAK,GAC1D;QAACC,UAAUpB,QAAQoB,QAAQ;QAAED,OAAO;IAAI,IACxC;QAACA,OAAO;QAAOK,kBAAkBxB,QAAQwB,gBAAgB;IAAA;IAE7D,iFAAiF;IACjF,wEAAwE;IACxE,2DAA2D;IAC3D,MAAMC,cAAcP,aAAa5B,KAAKoC,IAAI,CAACrB,SAAS,WAAW,WAAW,YAAYgB;IAEtF,OAAO;QACLzB,wBAAwB;YAAC6B;YAAaE,OAAOb;QAAS;QACtDhB,wBAAwByB;QACxB1B,yBAAyB;YAACkB;QAAS;QACnCpB,uBAAuB;YAACM,SAASqB;YAAmBpB;QAAI;KACzD;AACH,EAAC"}
1
+ {"version":3,"sources":["../../../../src/actions/build/vite/plugin.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {type ModuleFederationOptions} from '@module-federation/vite'\nimport {type PackageJson} from '@sanity/cli-core'\nimport {type PluginOption} from 'vite'\n\nimport {type WorkbenchExposes} from '../../../resolveWorkbenchApp.js'\nimport {artifactExposes, workbenchArtifacts} from '../artifact.js'\nimport {FEDERATION_FILE_NAME, RUNTIME_DIR} from './constants.js'\nimport {type FederationOptions, sanityModuleFederation} from './plugins/plugin-module-federation.js'\nimport {sanityEnvironmentPlugin} from './plugins/plugin-sanity-environment.js'\nimport {sanityExtensionArtifacts} from './plugins/plugin-sanity-extension-artifacts.js'\nimport {\n type FederationRuntimeOptions,\n sanityFederationRuntime,\n} from './plugins/plugin-sanity-federation-runtime.js'\n\ninterface FederationPluginOptionsBase extends Omit<Partial<FederationOptions>, 'exposes'> {\n exposes?: WorkbenchExposes\n /** Blueprints build (via `@sanity/runtime-cli`) — emit the resource-bindings module. */\n isBlueprints?: boolean\n pkgJson?: PackageJson\n /**\n * Current working directory to read package.json from, defaults to process.cwd()\n */\n workDir?: string\n}\n\ninterface AppFederationPluginOptions extends FederationPluginOptionsBase {\n isApp: true\n\n /**\n * Relative path to the App entry from the runtime directory, e.g.\n * `../../src/App.tsx`. Omit it for a dock-only app that declares no `entry`:\n * no `./App` is exposed and the remote serves only its views.\n */\n appEntry?: string\n studioConfigPath?: never\n}\n\ninterface StudioFederationPluginOptions extends FederationPluginOptionsBase {\n /** relative path to the Studio config file from the runtime directory (e.g. `../../sanity.config.ts`). */\n studioConfigPath: string\n\n appEntry?: never\n /** @defaultValue false */\n isApp?: false\n}\n\n/**\n * Plugin options for the federation vite plugin.\n *\n * Discriminated on `isApp`:\n * - `isApp: true` → requires `appEntry`\n * - `isApp: false` (default) → requires `studioConfigPath`\n *\n * @internal\n */\ntype FederationPluginOptions = AppFederationPluginOptions | StudioFederationPluginOptions\n\n/**\n * @internal\n */\nexport const federation = (options: FederationPluginOptions): PluginOption => {\n const {exposes, isBlueprints, name: defaultName, pkgJson, workDir = process.cwd()} = options\n\n let name = defaultName\n\n if (!name) {\n name = pkgJson?.name\n }\n\n if (!name) {\n throw new Error('\"name\" option is required but could not be inferred from package.json')\n }\n\n const generatedEntry = `./${RUNTIME_DIR}/${FEDERATION_FILE_NAME}.jsx`\n\n function resolveEntryPath(entry: string) {\n const resolvedPath = path.resolve(workDir, entry)\n\n if (!resolvedPath) {\n throw new Error(\n `Could not resolve path for entry \"${entry}\". Please check that the file exists and the path is correct.`,\n )\n }\n\n return resolvedPath\n }\n\n const entryPath = resolveEntryPath(generatedEntry)\n\n // Each view component (`./views/<view>/<component>`) and each service loader\n // (`./services/<name>`) is exposed straight to the host, pointing at the file\n // the extension-artifacts plugin generates under RUNTIME_DIR. A service's\n // worker bundle carries no expose — the host reaches it through its loader.\n const artifacts = workbenchArtifacts(exposes ?? {})\n const artifactModuleExposes = artifactExposes(artifacts, (artifactPath) =>\n resolveEntryPath(`./${RUNTIME_DIR}/${artifactPath}`),\n )\n\n // A dock-only app (`isApp` with no `appEntry`) has no navigable full-page\n // view, so it exposes no `./App` — only its views. Studios and apps with an\n // entry expose `./App` (the generated render entry).\n const exposesApp = !options.isApp || options.appEntry !== undefined\n\n const federationExposes: NonNullable<ModuleFederationOptions['exposes']> = {\n ...(exposesApp ? {'./App': entryPath} : {}),\n ...artifactModuleExposes,\n }\n\n const runtimeOptions: FederationRuntimeOptions = options.isApp\n ? {appEntry: options.appEntry, isApp: true, isBlueprints}\n : {isApp: false, isBlueprints, studioConfigPath: options.studioConfigPath}\n\n // Every federated app and studio also serves itself standalone. Whenever there's\n // an `./App` to mount (never for a dock-only app), build the SPA client\n // environment from the runtime bootstrap cli-build writes.\n const clientInput = exposesApp ? path.join(workDir, '.sanity', 'runtime', 'app.js') : undefined\n\n return [\n sanityEnvironmentPlugin({clientInput, input: entryPath, isBlueprints}),\n sanityFederationRuntime(runtimeOptions),\n sanityExtensionArtifacts({artifacts}),\n sanityModuleFederation({exposes: federationExposes, name}),\n ]\n}\n"],"names":["path","artifactExposes","workbenchArtifacts","FEDERATION_FILE_NAME","RUNTIME_DIR","sanityModuleFederation","sanityEnvironmentPlugin","sanityExtensionArtifacts","sanityFederationRuntime","federation","options","exposes","isBlueprints","name","defaultName","pkgJson","workDir","process","cwd","Error","generatedEntry","resolveEntryPath","entry","resolvedPath","resolve","entryPath","artifacts","artifactModuleExposes","artifactPath","exposesApp","isApp","appEntry","undefined","federationExposes","runtimeOptions","studioConfigPath","clientInput","join","input"],"mappings":"AAAA,OAAOA,UAAU,YAAW;AAO5B,SAAQC,eAAe,EAAEC,kBAAkB,QAAO,iBAAgB;AAClE,SAAQC,oBAAoB,EAAEC,WAAW,QAAO,iBAAgB;AAChE,SAAgCC,sBAAsB,QAAO,wCAAuC;AACpG,SAAQC,uBAAuB,QAAO,yCAAwC;AAC9E,SAAQC,wBAAwB,QAAO,iDAAgD;AACvF,SAEEC,uBAAuB,QAClB,gDAA+C;AA6CtD;;CAEC,GACD,OAAO,MAAMC,aAAa,CAACC;IACzB,MAAM,EAACC,OAAO,EAAEC,YAAY,EAAEC,MAAMC,WAAW,EAAEC,OAAO,EAAEC,UAAUC,QAAQC,GAAG,EAAE,EAAC,GAAGR;IAErF,IAAIG,OAAOC;IAEX,IAAI,CAACD,MAAM;QACTA,OAAOE,SAASF;IAClB;IAEA,IAAI,CAACA,MAAM;QACT,MAAM,IAAIM,MAAM;IAClB;IAEA,MAAMC,iBAAiB,CAAC,EAAE,EAAEhB,YAAY,CAAC,EAAED,qBAAqB,IAAI,CAAC;IAErE,SAASkB,iBAAiBC,KAAa;QACrC,MAAMC,eAAevB,KAAKwB,OAAO,CAACR,SAASM;QAE3C,IAAI,CAACC,cAAc;YACjB,MAAM,IAAIJ,MACR,CAAC,kCAAkC,EAAEG,MAAM,6DAA6D,CAAC;QAE7G;QAEA,OAAOC;IACT;IAEA,MAAME,YAAYJ,iBAAiBD;IAEnC,6EAA6E;IAC7E,8EAA8E;IAC9E,0EAA0E;IAC1E,4EAA4E;IAC5E,MAAMM,YAAYxB,mBAAmBS,WAAW,CAAC;IACjD,MAAMgB,wBAAwB1B,gBAAgByB,WAAW,CAACE,eACxDP,iBAAiB,CAAC,EAAE,EAAEjB,YAAY,CAAC,EAAEwB,cAAc;IAGrD,0EAA0E;IAC1E,4EAA4E;IAC5E,qDAAqD;IACrD,MAAMC,aAAa,CAACnB,QAAQoB,KAAK,IAAIpB,QAAQqB,QAAQ,KAAKC;IAE1D,MAAMC,oBAAqE;QACzE,GAAIJ,aAAa;YAAC,SAASJ;QAAS,IAAI,CAAC,CAAC;QAC1C,GAAGE,qBAAqB;IAC1B;IAEA,MAAMO,iBAA2CxB,QAAQoB,KAAK,GAC1D;QAACC,UAAUrB,QAAQqB,QAAQ;QAAED,OAAO;QAAMlB;IAAY,IACtD;QAACkB,OAAO;QAAOlB;QAAcuB,kBAAkBzB,QAAQyB,gBAAgB;IAAA;IAE3E,iFAAiF;IACjF,wEAAwE;IACxE,2DAA2D;IAC3D,MAAMC,cAAcP,aAAa7B,KAAKqC,IAAI,CAACrB,SAAS,WAAW,WAAW,YAAYgB;IAEtF,OAAO;QACL1B,wBAAwB;YAAC8B;YAAaE,OAAOb;YAAWb;QAAY;QACpEJ,wBAAwB0B;QACxB3B,yBAAyB;YAACmB;QAAS;QACnCrB,uBAAuB;YAACM,SAASsB;YAAmBpB;QAAI;KACzD;AACH,EAAC"}
@@ -1,6 +1,23 @@
1
+ import { resourceBindingsChunkFileName, resourceBindingsCodeSplittingGroup } from '../../resource-bindings.js';
1
2
  import { FEDERATION_DIR_NAME } from '../constants.js';
3
+ // Keep the resource-bindings module in its own unhashed chunk at the bundle root
4
+ // so Brett can rewrite it at deploy. `@module-federation/vite` preserves user
5
+ // `codeSplitting` groups (clamped below its own), so this survives the federation
6
+ // build. The chunk sizing lives on the group itself (see
7
+ // `resourceBindingsCodeSplittingGroup`), so it only affects the bindings module.
8
+ const resourceBindingsOutput = {
9
+ chunkFileNames: (chunk)=>resourceBindingsChunkFileName(chunk.name) ?? 'static/[name]-[hash].js',
10
+ codeSplitting: {
11
+ groups: [
12
+ resourceBindingsCodeSplittingGroup
13
+ ]
14
+ }
15
+ };
2
16
  export function sanityEnvironmentPlugin(options) {
3
- const { clientInput, input } = options;
17
+ const { clientInput, input, isBlueprints } = options;
18
+ // Blueprints only: force the resource-bindings module into its own unhashed
19
+ // chunk so Brett can rewrite it at deploy. Off Blueprints, no such chunk.
20
+ const output = isBlueprints ? resourceBindingsOutput : undefined;
4
21
  return {
5
22
  config () {
6
23
  return {
@@ -26,7 +43,8 @@ export function sanityEnvironmentPlugin(options) {
26
43
  rolldownOptions: {
27
44
  input: {
28
45
  sanity: clientInput
29
- }
46
+ },
47
+ output
30
48
  }
31
49
  },
32
50
  consumer: 'client'
@@ -39,7 +57,8 @@ export function sanityEnvironmentPlugin(options) {
39
57
  emptyOutDir: false,
40
58
  outDir: `dist`,
41
59
  rolldownOptions: {
42
- input
60
+ input,
61
+ output
43
62
  }
44
63
  },
45
64
  consumer: 'client'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/actions/build/vite/plugins/plugin-sanity-environment.ts"],"sourcesContent":["import {type Plugin} from 'vite'\n\nimport {FEDERATION_DIR_NAME} from '../constants.js'\n\ninterface EnvironmentOptions {\n input: string\n\n /**\n * When set, also build a standalone `client` SPA environment (its own\n * `index.html` + bootstrap) alongside the federation remote, from this entry.\n * Set for every federated app and studio; omitted only for a dock-only app.\n */\n clientInput?: string\n}\n\nexport function sanityEnvironmentPlugin(options: EnvironmentOptions): Plugin {\n const {clientInput, input} = options\n\n return {\n config() {\n return {\n builder: {\n async buildApp(builder) {\n // `emptyOutDir` is false on both environments and the CLI clears\n // `dist` once up-front, so the SPA and federation outputs coexist\n // without either build wiping the other's files.\n if (clientInput) {\n await builder.build(builder.environments.client)\n }\n await builder.build(builder.environments[FEDERATION_DIR_NAME])\n },\n },\n environments: {\n ...(clientInput\n ? {\n client: {\n build: {\n assetsDir: 'static',\n copyPublicDir: false,\n emptyOutDir: false,\n outDir: `dist`,\n rolldownOptions: {input: {sanity: clientInput}},\n },\n consumer: 'client',\n },\n }\n : {}),\n [FEDERATION_DIR_NAME]: {\n build: {\n assetsDir: 'static',\n copyPublicDir: false,\n emptyOutDir: false,\n outDir: `dist`,\n rolldownOptions: {input},\n },\n consumer: 'client',\n },\n },\n }\n },\n name: 'sanity/environment',\n }\n}\n"],"names":["FEDERATION_DIR_NAME","sanityEnvironmentPlugin","options","clientInput","input","config","builder","buildApp","build","environments","client","assetsDir","copyPublicDir","emptyOutDir","outDir","rolldownOptions","sanity","consumer","name"],"mappings":"AAEA,SAAQA,mBAAmB,QAAO,kBAAiB;AAanD,OAAO,SAASC,wBAAwBC,OAA2B;IACjE,MAAM,EAACC,WAAW,EAAEC,KAAK,EAAC,GAAGF;IAE7B,OAAO;QACLG;YACE,OAAO;gBACLC,SAAS;oBACP,MAAMC,UAASD,OAAO;wBACpB,iEAAiE;wBACjE,kEAAkE;wBAClE,iDAAiD;wBACjD,IAAIH,aAAa;4BACf,MAAMG,QAAQE,KAAK,CAACF,QAAQG,YAAY,CAACC,MAAM;wBACjD;wBACA,MAAMJ,QAAQE,KAAK,CAACF,QAAQG,YAAY,CAACT,oBAAoB;oBAC/D;gBACF;gBACAS,cAAc;oBACZ,GAAIN,cACA;wBACEO,QAAQ;4BACNF,OAAO;gCACLG,WAAW;gCACXC,eAAe;gCACfC,aAAa;gCACbC,QAAQ,CAAC,IAAI,CAAC;gCACdC,iBAAiB;oCAACX,OAAO;wCAACY,QAAQb;oCAAW;gCAAC;4BAChD;4BACAc,UAAU;wBACZ;oBACF,IACA,CAAC,CAAC;oBACN,CAACjB,oBAAoB,EAAE;wBACrBQ,OAAO;4BACLG,WAAW;4BACXC,eAAe;4BACfC,aAAa;4BACbC,QAAQ,CAAC,IAAI,CAAC;4BACdC,iBAAiB;gCAACX;4BAAK;wBACzB;wBACAa,UAAU;oBACZ;gBACF;YACF;QACF;QACAC,MAAM;IACR;AACF"}
1
+ {"version":3,"sources":["../../../../../src/actions/build/vite/plugins/plugin-sanity-environment.ts"],"sourcesContent":["import {type Plugin} from 'vite'\n\nimport {\n resourceBindingsChunkFileName,\n resourceBindingsCodeSplittingGroup,\n} from '../../resource-bindings.js'\nimport {FEDERATION_DIR_NAME} from '../constants.js'\n\n// Keep the resource-bindings module in its own unhashed chunk at the bundle root\n// so Brett can rewrite it at deploy. `@module-federation/vite` preserves user\n// `codeSplitting` groups (clamped below its own), so this survives the federation\n// build. The chunk sizing lives on the group itself (see\n// `resourceBindingsCodeSplittingGroup`), so it only affects the bindings module.\nconst resourceBindingsOutput = {\n chunkFileNames: (chunk: {name: string}) =>\n resourceBindingsChunkFileName(chunk.name) ?? 'static/[name]-[hash].js',\n codeSplitting: {\n groups: [resourceBindingsCodeSplittingGroup],\n },\n}\n\ninterface EnvironmentOptions {\n input: string\n\n /**\n * When set, also build a standalone `client` SPA environment (its own\n * `index.html` + bootstrap) alongside the federation remote, from this entry.\n * Set for every federated app and studio; omitted only for a dock-only app.\n */\n clientInput?: string\n\n /** Blueprints build (via `@sanity/runtime-cli`) — emit the resource-bindings module. */\n isBlueprints?: boolean\n}\n\nexport function sanityEnvironmentPlugin(options: EnvironmentOptions): Plugin {\n const {clientInput, input, isBlueprints} = options\n\n // Blueprints only: force the resource-bindings module into its own unhashed\n // chunk so Brett can rewrite it at deploy. Off Blueprints, no such chunk.\n const output = isBlueprints ? resourceBindingsOutput : undefined\n\n return {\n config() {\n return {\n builder: {\n async buildApp(builder) {\n // `emptyOutDir` is false on both environments and the CLI clears\n // `dist` once up-front, so the SPA and federation outputs coexist\n // without either build wiping the other's files.\n if (clientInput) {\n await builder.build(builder.environments.client)\n }\n await builder.build(builder.environments[FEDERATION_DIR_NAME])\n },\n },\n environments: {\n ...(clientInput\n ? {\n client: {\n build: {\n assetsDir: 'static',\n copyPublicDir: false,\n emptyOutDir: false,\n outDir: `dist`,\n rolldownOptions: {\n input: {sanity: clientInput},\n output,\n },\n },\n consumer: 'client',\n },\n }\n : {}),\n [FEDERATION_DIR_NAME]: {\n build: {\n assetsDir: 'static',\n copyPublicDir: false,\n emptyOutDir: false,\n outDir: `dist`,\n rolldownOptions: {input, output},\n },\n consumer: 'client',\n },\n },\n }\n },\n name: 'sanity/environment',\n }\n}\n"],"names":["resourceBindingsChunkFileName","resourceBindingsCodeSplittingGroup","FEDERATION_DIR_NAME","resourceBindingsOutput","chunkFileNames","chunk","name","codeSplitting","groups","sanityEnvironmentPlugin","options","clientInput","input","isBlueprints","output","undefined","config","builder","buildApp","build","environments","client","assetsDir","copyPublicDir","emptyOutDir","outDir","rolldownOptions","sanity","consumer"],"mappings":"AAEA,SACEA,6BAA6B,EAC7BC,kCAAkC,QAC7B,6BAA4B;AACnC,SAAQC,mBAAmB,QAAO,kBAAiB;AAEnD,iFAAiF;AACjF,8EAA8E;AAC9E,kFAAkF;AAClF,yDAAyD;AACzD,iFAAiF;AACjF,MAAMC,yBAAyB;IAC7BC,gBAAgB,CAACC,QACfL,8BAA8BK,MAAMC,IAAI,KAAK;IAC/CC,eAAe;QACbC,QAAQ;YAACP;SAAmC;IAC9C;AACF;AAgBA,OAAO,SAASQ,wBAAwBC,OAA2B;IACjE,MAAM,EAACC,WAAW,EAAEC,KAAK,EAAEC,YAAY,EAAC,GAAGH;IAE3C,4EAA4E;IAC5E,0EAA0E;IAC1E,MAAMI,SAASD,eAAeV,yBAAyBY;IAEvD,OAAO;QACLC;YACE,OAAO;gBACLC,SAAS;oBACP,MAAMC,UAASD,OAAO;wBACpB,iEAAiE;wBACjE,kEAAkE;wBAClE,iDAAiD;wBACjD,IAAIN,aAAa;4BACf,MAAMM,QAAQE,KAAK,CAACF,QAAQG,YAAY,CAACC,MAAM;wBACjD;wBACA,MAAMJ,QAAQE,KAAK,CAACF,QAAQG,YAAY,CAAClB,oBAAoB;oBAC/D;gBACF;gBACAkB,cAAc;oBACZ,GAAIT,cACA;wBACEU,QAAQ;4BACNF,OAAO;gCACLG,WAAW;gCACXC,eAAe;gCACfC,aAAa;gCACbC,QAAQ,CAAC,IAAI,CAAC;gCACdC,iBAAiB;oCACfd,OAAO;wCAACe,QAAQhB;oCAAW;oCAC3BG;gCACF;4BACF;4BACAc,UAAU;wBACZ;oBACF,IACA,CAAC,CAAC;oBACN,CAAC1B,oBAAoB,EAAE;wBACrBiB,OAAO;4BACLG,WAAW;4BACXC,eAAe;4BACfC,aAAa;4BACbC,QAAQ,CAAC,IAAI,CAAC;4BACdC,iBAAiB;gCAACd;gCAAOE;4BAAM;wBACjC;wBACAc,UAAU;oBACZ;gBACF;YACF;QACF;QACAtB,MAAM;IACR;AACF"}
@@ -1,20 +1,22 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { renderRemote } from '../../render-remote.js';
4
+ import { RESOURCE_BINDINGS_ENTRY_IMPORT, RESOURCE_BINDINGS_FILENAME, RESOURCE_BINDINGS_MODULE_SOURCE } from '../../resource-bindings.js';
4
5
  import { FEDERATION_FILE_NAME, RUNTIME_DIR } from '../constants.js';
5
6
  const REMOTE_ENTRY_FILE = `${FEDERATION_FILE_NAME}.jsx`;
6
7
  // The studio wraps `Studio` with the user's config; HMR re-renders through the
7
- // new module so a config edit takes effect.
8
+ // new module so a config edit takes effect. The `%RESOURCE_BINDINGS_IMPORT%`
9
+ // placeholder is filled in per-build (Blueprints only — see below).
8
10
  const STUDIO_ENTRY = renderRemote({
9
11
  app: `(props) => createElement(Studio, { config, ...props })`,
10
12
  hmr: true,
11
- preamble: `import { Studio } from 'sanity'
13
+ preamble: `%RESOURCE_BINDINGS_IMPORT%import { Studio } from 'sanity'
12
14
  import config from %STUDIO_CONFIG%`
13
15
  });
14
16
  // An SDK app's default export is the component; it Fast-Refreshes through its
15
17
  // own dev server, so the wrapper needs no HMR boundary.
16
18
  const APP_ENTRY = renderRemote({
17
- preamble: `import App from %APP_ENTRY%`
19
+ preamble: `%RESOURCE_BINDINGS_IMPORT%import App from %APP_ENTRY%`
18
20
  });
19
21
  // A branded app that declares no `entry` (e.g. a dock-only panel/worker app)
20
22
  // has no navigable full-page view, so there's no `App` to import. The runtime
@@ -25,17 +27,23 @@ const HEADLESS_APP_ENTRY = `\
25
27
  // Modifications to this file are automatically discarded
26
28
  // This application declares no app view (no \`entry\`): it isn't navigable as a
27
29
  // full-page app, only its panels/web workers are exposed.
28
- export function render() {
30
+ %RESOURCE_BINDINGS_IMPORT%export function render() {
29
31
  throw new Error('This application has no app view: it declares no \`entry\`.')
30
32
  }
31
33
  `;
32
34
  export function sanityFederationRuntime(options) {
35
+ const { isBlueprints } = options;
33
36
  let content;
34
37
  if (options.isApp) {
35
38
  content = options.appEntry ? APP_ENTRY.replace(/%APP_ENTRY%/, JSON.stringify(options.appEntry)) : HEADLESS_APP_ENTRY;
36
39
  } else {
37
40
  content = STUDIO_ENTRY.replace(/%STUDIO_CONFIG%/, JSON.stringify(options.studioConfigPath));
38
41
  }
42
+ // Blueprints only: the remote entry statically imports the resource-bindings
43
+ // module first, so bindings evaluate before app code. Off Blueprints the
44
+ // placeholder resolves to nothing and the module is neither imported nor
45
+ // written below.
46
+ content = content.replace(/%RESOURCE_BINDINGS_IMPORT%/, isBlueprints ? `${RESOURCE_BINDINGS_ENTRY_IMPORT}\n` : '');
39
47
  let entryFileAbsPath = '';
40
48
  return {
41
49
  configResolved (config) {
@@ -45,6 +53,10 @@ export function sanityFederationRuntime(options) {
45
53
  recursive: true
46
54
  });
47
55
  fs.writeFileSync(entryFileAbsPath, content);
56
+ if (isBlueprints) {
57
+ // Brett bakes the resolved values into this module at deploy.
58
+ fs.writeFileSync(path.join(dir, RESOURCE_BINDINGS_FILENAME), RESOURCE_BINDINGS_MODULE_SOURCE);
59
+ }
48
60
  },
49
61
  hotUpdate ({ file, modules, timestamp }) {
50
62
  if (options.isApp) return;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/actions/build/vite/plugins/plugin-sanity-federation-runtime.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\nimport {type EnvironmentModuleNode, type Plugin} from 'vite'\n\nimport {renderRemote} from '../../render-remote.js'\nimport {FEDERATION_FILE_NAME, RUNTIME_DIR} from '../constants.js'\n\nconst REMOTE_ENTRY_FILE = `${FEDERATION_FILE_NAME}.jsx`\n\n// The studio wraps `Studio` with the user's config; HMR re-renders through the\n// new module so a config edit takes effect.\nconst STUDIO_ENTRY = renderRemote({\n app: `(props) => createElement(Studio, { config, ...props })`,\n hmr: true,\n preamble: `import { Studio } from 'sanity'\nimport config from %STUDIO_CONFIG%`,\n})\n\n// An SDK app's default export is the component; it Fast-Refreshes through its\n// own dev server, so the wrapper needs no HMR boundary.\nconst APP_ENTRY = renderRemote({preamble: `import App from %APP_ENTRY%`})\n\n// A branded app that declares no `entry` (e.g. a dock-only panel/worker app)\n// has no navigable full-page view, so there's no `App` to import. The runtime\n// still needs a valid module for the federation build input, but it exposes no\n// `./App` (see `plugin.ts`) — its `render` is unreachable and throws if reached.\nconst HEADLESS_APP_ENTRY = `\\\n// This file is auto-generated on 'sanity dev'\n// Modifications to this file are automatically discarded\n// This application declares no app view (no \\`entry\\`): it isn't navigable as a\n// full-page app, only its panels/web workers are exposed.\nexport function render() {\n throw new Error('This application has no app view: it declares no \\`entry\\`.')\n}\n`\n\nexport type FederationRuntimeOptions =\n | {appEntry?: string; isApp: true}\n | {isApp: false; studioConfigPath: string}\n\nexport function sanityFederationRuntime(options: FederationRuntimeOptions): Plugin {\n let content: string\n if (options.isApp) {\n content = options.appEntry\n ? APP_ENTRY.replace(/%APP_ENTRY%/, JSON.stringify(options.appEntry))\n : HEADLESS_APP_ENTRY\n } else {\n content = STUDIO_ENTRY.replace(/%STUDIO_CONFIG%/, JSON.stringify(options.studioConfigPath))\n }\n\n let entryFileAbsPath = ''\n\n return {\n configResolved(config) {\n const dir = path.resolve(config.root, RUNTIME_DIR)\n entryFileAbsPath = path.join(dir, REMOTE_ENTRY_FILE)\n\n fs.mkdirSync(dir, {recursive: true})\n fs.writeFileSync(entryFileAbsPath, content)\n },\n hotUpdate({file, modules, timestamp}) {\n if (options.isApp) return\n if (this.environment.name !== 'client') return\n\n const {moduleGraph} = this.environment\n const studioMods = moduleGraph.getModulesByFile(entryFileAbsPath)\n if (!studioMods?.size) return\n\n // Is the changed file reachable from the studio entry?\n const visited = new Set<EnvironmentModuleNode>()\n const queue: EnvironmentModuleNode[] = [...studioMods]\n while (queue.length > 0) {\n const mod = queue.pop()!\n if (visited.has(mod)) continue\n visited.add(mod)\n if (mod.file === file) {\n // The walk from `file` up through importers dead-ends at federation\n // gaps, so invalidate changed modules ourselves and route HMR to the\n // self-accepting studio entry.\n const seen = new Set<EnvironmentModuleNode>()\n for (const m of modules) {\n moduleGraph.invalidateModule(m, seen, timestamp, true)\n }\n return [...studioMods]\n }\n for (const dep of mod.importedModules) queue.push(dep)\n }\n },\n name: 'sanity/federation-runtime',\n }\n}\n"],"names":["fs","path","renderRemote","FEDERATION_FILE_NAME","RUNTIME_DIR","REMOTE_ENTRY_FILE","STUDIO_ENTRY","app","hmr","preamble","APP_ENTRY","HEADLESS_APP_ENTRY","sanityFederationRuntime","options","content","isApp","appEntry","replace","JSON","stringify","studioConfigPath","entryFileAbsPath","configResolved","config","dir","resolve","root","join","mkdirSync","recursive","writeFileSync","hotUpdate","file","modules","timestamp","environment","name","moduleGraph","studioMods","getModulesByFile","size","visited","Set","queue","length","mod","pop","has","add","seen","m","invalidateModule","dep","importedModules","push"],"mappings":"AAAA,OAAOA,QAAQ,UAAS;AACxB,OAAOC,UAAU,YAAW;AAI5B,SAAQC,YAAY,QAAO,yBAAwB;AACnD,SAAQC,oBAAoB,EAAEC,WAAW,QAAO,kBAAiB;AAEjE,MAAMC,oBAAoB,GAAGF,qBAAqB,IAAI,CAAC;AAEvD,+EAA+E;AAC/E,4CAA4C;AAC5C,MAAMG,eAAeJ,aAAa;IAChCK,KAAK,CAAC,sDAAsD,CAAC;IAC7DC,KAAK;IACLC,UAAU,CAAC;kCACqB,CAAC;AACnC;AAEA,8EAA8E;AAC9E,wDAAwD;AACxD,MAAMC,YAAYR,aAAa;IAACO,UAAU,CAAC,2BAA2B,CAAC;AAAA;AAEvE,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,iFAAiF;AACjF,MAAME,qBAAqB,CAAC;;;;;;;;AAQ5B,CAAC;AAMD,OAAO,SAASC,wBAAwBC,OAAiC;IACvE,IAAIC;IACJ,IAAID,QAAQE,KAAK,EAAE;QACjBD,UAAUD,QAAQG,QAAQ,GACtBN,UAAUO,OAAO,CAAC,eAAeC,KAAKC,SAAS,CAACN,QAAQG,QAAQ,KAChEL;IACN,OAAO;QACLG,UAAUR,aAAaW,OAAO,CAAC,mBAAmBC,KAAKC,SAAS,CAACN,QAAQO,gBAAgB;IAC3F;IAEA,IAAIC,mBAAmB;IAEvB,OAAO;QACLC,gBAAeC,MAAM;YACnB,MAAMC,MAAMvB,KAAKwB,OAAO,CAACF,OAAOG,IAAI,EAAEtB;YACtCiB,mBAAmBpB,KAAK0B,IAAI,CAACH,KAAKnB;YAElCL,GAAG4B,SAAS,CAACJ,KAAK;gBAACK,WAAW;YAAI;YAClC7B,GAAG8B,aAAa,CAACT,kBAAkBP;QACrC;QACAiB,WAAU,EAACC,IAAI,EAAEC,OAAO,EAAEC,SAAS,EAAC;YAClC,IAAIrB,QAAQE,KAAK,EAAE;YACnB,IAAI,IAAI,CAACoB,WAAW,CAACC,IAAI,KAAK,UAAU;YAExC,MAAM,EAACC,WAAW,EAAC,GAAG,IAAI,CAACF,WAAW;YACtC,MAAMG,aAAaD,YAAYE,gBAAgB,CAAClB;YAChD,IAAI,CAACiB,YAAYE,MAAM;YAEvB,uDAAuD;YACvD,MAAMC,UAAU,IAAIC;YACpB,MAAMC,QAAiC;mBAAIL;aAAW;YACtD,MAAOK,MAAMC,MAAM,GAAG,EAAG;gBACvB,MAAMC,MAAMF,MAAMG,GAAG;gBACrB,IAAIL,QAAQM,GAAG,CAACF,MAAM;gBACtBJ,QAAQO,GAAG,CAACH;gBACZ,IAAIA,IAAIb,IAAI,KAAKA,MAAM;oBACrB,oEAAoE;oBACpE,qEAAqE;oBACrE,+BAA+B;oBAC/B,MAAMiB,OAAO,IAAIP;oBACjB,KAAK,MAAMQ,KAAKjB,QAAS;wBACvBI,YAAYc,gBAAgB,CAACD,GAAGD,MAAMf,WAAW;oBACnD;oBACA,OAAO;2BAAII;qBAAW;gBACxB;gBACA,KAAK,MAAMc,OAAOP,IAAIQ,eAAe,CAAEV,MAAMW,IAAI,CAACF;YACpD;QACF;QACAhB,MAAM;IACR;AACF"}
1
+ {"version":3,"sources":["../../../../../src/actions/build/vite/plugins/plugin-sanity-federation-runtime.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\nimport {type EnvironmentModuleNode, type Plugin} from 'vite'\n\nimport {renderRemote} from '../../render-remote.js'\nimport {\n RESOURCE_BINDINGS_ENTRY_IMPORT,\n RESOURCE_BINDINGS_FILENAME,\n RESOURCE_BINDINGS_MODULE_SOURCE,\n} from '../../resource-bindings.js'\nimport {FEDERATION_FILE_NAME, RUNTIME_DIR} from '../constants.js'\n\nconst REMOTE_ENTRY_FILE = `${FEDERATION_FILE_NAME}.jsx`\n\n// The studio wraps `Studio` with the user's config; HMR re-renders through the\n// new module so a config edit takes effect. The `%RESOURCE_BINDINGS_IMPORT%`\n// placeholder is filled in per-build (Blueprints only — see below).\nconst STUDIO_ENTRY = renderRemote({\n app: `(props) => createElement(Studio, { config, ...props })`,\n hmr: true,\n preamble: `%RESOURCE_BINDINGS_IMPORT%import { Studio } from 'sanity'\nimport config from %STUDIO_CONFIG%`,\n})\n\n// An SDK app's default export is the component; it Fast-Refreshes through its\n// own dev server, so the wrapper needs no HMR boundary.\nconst APP_ENTRY = renderRemote({\n preamble: `%RESOURCE_BINDINGS_IMPORT%import App from %APP_ENTRY%`,\n})\n\n// A branded app that declares no `entry` (e.g. a dock-only panel/worker app)\n// has no navigable full-page view, so there's no `App` to import. The runtime\n// still needs a valid module for the federation build input, but it exposes no\n// `./App` (see `plugin.ts`) — its `render` is unreachable and throws if reached.\nconst HEADLESS_APP_ENTRY = `\\\n// This file is auto-generated on 'sanity dev'\n// Modifications to this file are automatically discarded\n// This application declares no app view (no \\`entry\\`): it isn't navigable as a\n// full-page app, only its panels/web workers are exposed.\n%RESOURCE_BINDINGS_IMPORT%export function render() {\n throw new Error('This application has no app view: it declares no \\`entry\\`.')\n}\n`\n\nexport type FederationRuntimeOptions =\n | {appEntry?: string; isApp: true; isBlueprints?: boolean}\n | {isApp: false; isBlueprints?: boolean; studioConfigPath: string}\n\nexport function sanityFederationRuntime(options: FederationRuntimeOptions): Plugin {\n const {isBlueprints} = options\n\n let content: string\n if (options.isApp) {\n content = options.appEntry\n ? APP_ENTRY.replace(/%APP_ENTRY%/, JSON.stringify(options.appEntry))\n : HEADLESS_APP_ENTRY\n } else {\n content = STUDIO_ENTRY.replace(/%STUDIO_CONFIG%/, JSON.stringify(options.studioConfigPath))\n }\n\n // Blueprints only: the remote entry statically imports the resource-bindings\n // module first, so bindings evaluate before app code. Off Blueprints the\n // placeholder resolves to nothing and the module is neither imported nor\n // written below.\n content = content.replace(\n /%RESOURCE_BINDINGS_IMPORT%/,\n isBlueprints ? `${RESOURCE_BINDINGS_ENTRY_IMPORT}\\n` : '',\n )\n\n let entryFileAbsPath = ''\n\n return {\n configResolved(config) {\n const dir = path.resolve(config.root, RUNTIME_DIR)\n entryFileAbsPath = path.join(dir, REMOTE_ENTRY_FILE)\n\n fs.mkdirSync(dir, {recursive: true})\n fs.writeFileSync(entryFileAbsPath, content)\n\n if (isBlueprints) {\n // Brett bakes the resolved values into this module at deploy.\n fs.writeFileSync(\n path.join(dir, RESOURCE_BINDINGS_FILENAME),\n RESOURCE_BINDINGS_MODULE_SOURCE,\n )\n }\n },\n hotUpdate({file, modules, timestamp}) {\n if (options.isApp) return\n if (this.environment.name !== 'client') return\n\n const {moduleGraph} = this.environment\n const studioMods = moduleGraph.getModulesByFile(entryFileAbsPath)\n if (!studioMods?.size) return\n\n // Is the changed file reachable from the studio entry?\n const visited = new Set<EnvironmentModuleNode>()\n const queue: EnvironmentModuleNode[] = [...studioMods]\n while (queue.length > 0) {\n const mod = queue.pop()!\n if (visited.has(mod)) continue\n visited.add(mod)\n if (mod.file === file) {\n // The walk from `file` up through importers dead-ends at federation\n // gaps, so invalidate changed modules ourselves and route HMR to the\n // self-accepting studio entry.\n const seen = new Set<EnvironmentModuleNode>()\n for (const m of modules) {\n moduleGraph.invalidateModule(m, seen, timestamp, true)\n }\n return [...studioMods]\n }\n for (const dep of mod.importedModules) queue.push(dep)\n }\n },\n name: 'sanity/federation-runtime',\n }\n}\n"],"names":["fs","path","renderRemote","RESOURCE_BINDINGS_ENTRY_IMPORT","RESOURCE_BINDINGS_FILENAME","RESOURCE_BINDINGS_MODULE_SOURCE","FEDERATION_FILE_NAME","RUNTIME_DIR","REMOTE_ENTRY_FILE","STUDIO_ENTRY","app","hmr","preamble","APP_ENTRY","HEADLESS_APP_ENTRY","sanityFederationRuntime","options","isBlueprints","content","isApp","appEntry","replace","JSON","stringify","studioConfigPath","entryFileAbsPath","configResolved","config","dir","resolve","root","join","mkdirSync","recursive","writeFileSync","hotUpdate","file","modules","timestamp","environment","name","moduleGraph","studioMods","getModulesByFile","size","visited","Set","queue","length","mod","pop","has","add","seen","m","invalidateModule","dep","importedModules","push"],"mappings":"AAAA,OAAOA,QAAQ,UAAS;AACxB,OAAOC,UAAU,YAAW;AAI5B,SAAQC,YAAY,QAAO,yBAAwB;AACnD,SACEC,8BAA8B,EAC9BC,0BAA0B,EAC1BC,+BAA+B,QAC1B,6BAA4B;AACnC,SAAQC,oBAAoB,EAAEC,WAAW,QAAO,kBAAiB;AAEjE,MAAMC,oBAAoB,GAAGF,qBAAqB,IAAI,CAAC;AAEvD,+EAA+E;AAC/E,6EAA6E;AAC7E,oEAAoE;AACpE,MAAMG,eAAeP,aAAa;IAChCQ,KAAK,CAAC,sDAAsD,CAAC;IAC7DC,KAAK;IACLC,UAAU,CAAC;kCACqB,CAAC;AACnC;AAEA,8EAA8E;AAC9E,wDAAwD;AACxD,MAAMC,YAAYX,aAAa;IAC7BU,UAAU,CAAC,qDAAqD,CAAC;AACnE;AAEA,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,iFAAiF;AACjF,MAAME,qBAAqB,CAAC;;;;;;;;AAQ5B,CAAC;AAMD,OAAO,SAASC,wBAAwBC,OAAiC;IACvE,MAAM,EAACC,YAAY,EAAC,GAAGD;IAEvB,IAAIE;IACJ,IAAIF,QAAQG,KAAK,EAAE;QACjBD,UAAUF,QAAQI,QAAQ,GACtBP,UAAUQ,OAAO,CAAC,eAAeC,KAAKC,SAAS,CAACP,QAAQI,QAAQ,KAChEN;IACN,OAAO;QACLI,UAAUT,aAAaY,OAAO,CAAC,mBAAmBC,KAAKC,SAAS,CAACP,QAAQQ,gBAAgB;IAC3F;IAEA,6EAA6E;IAC7E,yEAAyE;IACzE,yEAAyE;IACzE,iBAAiB;IACjBN,UAAUA,QAAQG,OAAO,CACvB,8BACAJ,eAAe,GAAGd,+BAA+B,EAAE,CAAC,GAAG;IAGzD,IAAIsB,mBAAmB;IAEvB,OAAO;QACLC,gBAAeC,MAAM;YACnB,MAAMC,MAAM3B,KAAK4B,OAAO,CAACF,OAAOG,IAAI,EAAEvB;YACtCkB,mBAAmBxB,KAAK8B,IAAI,CAACH,KAAKpB;YAElCR,GAAGgC,SAAS,CAACJ,KAAK;gBAACK,WAAW;YAAI;YAClCjC,GAAGkC,aAAa,CAACT,kBAAkBP;YAEnC,IAAID,cAAc;gBAChB,8DAA8D;gBAC9DjB,GAAGkC,aAAa,CACdjC,KAAK8B,IAAI,CAACH,KAAKxB,6BACfC;YAEJ;QACF;QACA8B,WAAU,EAACC,IAAI,EAAEC,OAAO,EAAEC,SAAS,EAAC;YAClC,IAAItB,QAAQG,KAAK,EAAE;YACnB,IAAI,IAAI,CAACoB,WAAW,CAACC,IAAI,KAAK,UAAU;YAExC,MAAM,EAACC,WAAW,EAAC,GAAG,IAAI,CAACF,WAAW;YACtC,MAAMG,aAAaD,YAAYE,gBAAgB,CAAClB;YAChD,IAAI,CAACiB,YAAYE,MAAM;YAEvB,uDAAuD;YACvD,MAAMC,UAAU,IAAIC;YACpB,MAAMC,QAAiC;mBAAIL;aAAW;YACtD,MAAOK,MAAMC,MAAM,GAAG,EAAG;gBACvB,MAAMC,MAAMF,MAAMG,GAAG;gBACrB,IAAIL,QAAQM,GAAG,CAACF,MAAM;gBACtBJ,QAAQO,GAAG,CAACH;gBACZ,IAAIA,IAAIb,IAAI,KAAKA,MAAM;oBACrB,oEAAoE;oBACpE,qEAAqE;oBACrE,+BAA+B;oBAC/B,MAAMiB,OAAO,IAAIP;oBACjB,KAAK,MAAMQ,KAAKjB,QAAS;wBACvBI,YAAYc,gBAAgB,CAACD,GAAGD,MAAMf,WAAW;oBACnD;oBACA,OAAO;2BAAII;qBAAW;gBACxB;gBACA,KAAK,MAAMc,OAAOP,IAAIQ,eAAe,CAAEV,MAAMW,IAAI,CAACF;YACpD;QACF;QACAhB,MAAM;IACR;AACF"}
@@ -20,7 +20,7 @@ import { sanityAppId } from './plugins/plugin-sanity-app-id.js';
20
20
  return relativeConfigLocation;
21
21
  }
22
22
  /** Build the Vite plugins for a workbench app's module-federation remote. */ export async function workbenchVitePlugins(options) {
23
- const { appId, cwd, entries, exposes, isApp } = options;
23
+ const { appId, cwd, entries, exposes, isApp, isBlueprints } = options;
24
24
  const pkgJson = await readPackageJson(path.join(cwd, 'package.json'));
25
25
  const federationPlugin = federation({
26
26
  ...isApp ? {
@@ -35,6 +35,7 @@ import { sanityAppId } from './plugins/plugin-sanity-app-id.js';
35
35
  studioConfigPath: requireStudioConfigPath(entries.relativeConfigLocation)
36
36
  },
37
37
  exposes,
38
+ isBlueprints,
38
39
  pkgJson,
39
40
  workDir: cwd
40
41
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/actions/build/vite/workbench-vite-plugins.ts"],"sourcesContent":["// The build-facing entry of the workbench federation stack: turn a workbench\n// app's build inputs into the Vite plugins that produce its module-federation\n// remote. `@sanity/cli-build`'s `getViteConfig` calls this instead of\n// assembling `federation`'s options itself, so the discriminated app-vs-studio\n// option shape, the no-app-view rule, and the studio-config requirement all\n// live here next to `federation` — the build package just hands over its inputs.\n\nimport path from 'node:path'\n\nimport {readPackageJson} from '@sanity/cli-core'\nimport {type PluginOption} from 'vite'\n\nimport {type WorkbenchExposes} from '../../../resolveWorkbenchApp.js'\nimport {federation} from './plugin.js'\nimport {sanityAppId} from './plugins/plugin-sanity-app-id.js'\n\ninterface WorkbenchViteOptions {\n /** Project root — read for the federation remote name, and the plugin workDir. */\n cwd: string\n /**\n * Build entry paths relative to the federation runtime dir. `relativeEntry` is\n * the app's `entry` (null for a dock-only app with no app view);\n * `relativeConfigLocation` is the studio's `sanity.config.*` (null when absent).\n */\n entries: {relativeConfigLocation: string | null; relativeEntry: string | null}\n\n /** The app's bus identity, stamped into its modules for `@sanity/runtime`. */\n appId?: string\n\n exposes?: WorkbenchExposes\n /** App (vs studio) build — selects the discriminated federation option shape. */\n isApp?: boolean\n}\n\n/**\n * A workbench studio renders from its `sanity.config.*`, so the build needs one.\n * An explicit `applicationType: 'studio'` wins over detection, so a studio can\n * reach here with no config file — fail with the fix rather than a cryptic build\n * error downstream.\n */\nfunction requireStudioConfigPath(relativeConfigLocation: string | null): string {\n if (relativeConfigLocation === null) {\n throw new Error(\n 'Workbench studios need a sanity.config.js or sanity.config.ts file. ' +\n \"Add one, or remove `applicationType: 'studio'` from `defineApplication` \" +\n 'to let the CLI infer the application type.',\n )\n }\n return relativeConfigLocation\n}\n\n/** Build the Vite plugins for a workbench app's module-federation remote. */\nexport async function workbenchVitePlugins(options: WorkbenchViteOptions): Promise<PluginOption> {\n const {appId, cwd, entries, exposes, isApp} = options\n const pkgJson = await readPackageJson(path.join(cwd, 'package.json'))\n\n const federationPlugin = federation({\n ...(isApp\n ? {\n // `null` relativeEntry (a branded app with no `entry`) → omit `appEntry`,\n // so the remote exposes no `./App`, only its views.\n ...(entries.relativeEntry ? {appEntry: entries.relativeEntry} : {}),\n isApp: true as const,\n }\n : {\n isApp: false as const,\n studioConfigPath: requireStudioConfigPath(entries.relativeConfigLocation),\n }),\n exposes,\n pkgJson,\n workDir: cwd,\n })\n\n return appId === undefined ? federationPlugin : [federationPlugin, sanityAppId(appId)]\n}\n"],"names":["path","readPackageJson","federation","sanityAppId","requireStudioConfigPath","relativeConfigLocation","Error","workbenchVitePlugins","options","appId","cwd","entries","exposes","isApp","pkgJson","join","federationPlugin","relativeEntry","appEntry","studioConfigPath","workDir","undefined"],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,sEAAsE;AACtE,+EAA+E;AAC/E,4EAA4E;AAC5E,iFAAiF;AAEjF,OAAOA,UAAU,YAAW;AAE5B,SAAQC,eAAe,QAAO,mBAAkB;AAIhD,SAAQC,UAAU,QAAO,cAAa;AACtC,SAAQC,WAAW,QAAO,oCAAmC;AAoB7D;;;;;CAKC,GACD,SAASC,wBAAwBC,sBAAqC;IACpE,IAAIA,2BAA2B,MAAM;QACnC,MAAM,IAAIC,MACR,yEACE,6EACA;IAEN;IACA,OAAOD;AACT;AAEA,2EAA2E,GAC3E,OAAO,eAAeE,qBAAqBC,OAA6B;IACtE,MAAM,EAACC,KAAK,EAAEC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,KAAK,EAAC,GAAGL;IAC9C,MAAMM,UAAU,MAAMb,gBAAgBD,KAAKe,IAAI,CAACL,KAAK;IAErD,MAAMM,mBAAmBd,WAAW;QAClC,GAAIW,QACA;YACE,0EAA0E;YAC1E,oDAAoD;YACpD,GAAIF,QAAQM,aAAa,GAAG;gBAACC,UAAUP,QAAQM,aAAa;YAAA,IAAI,CAAC,CAAC;YAClEJ,OAAO;QACT,IACA;YACEA,OAAO;YACPM,kBAAkBf,wBAAwBO,QAAQN,sBAAsB;QAC1E,CAAC;QACLO;QACAE;QACAM,SAASV;IACX;IAEA,OAAOD,UAAUY,YAAYL,mBAAmB;QAACA;QAAkBb,YAAYM;KAAO;AACxF"}
1
+ {"version":3,"sources":["../../../../src/actions/build/vite/workbench-vite-plugins.ts"],"sourcesContent":["// The build-facing entry of the workbench federation stack: turn a workbench\n// app's build inputs into the Vite plugins that produce its module-federation\n// remote. `@sanity/cli-build`'s `getViteConfig` calls this instead of\n// assembling `federation`'s options itself, so the discriminated app-vs-studio\n// option shape, the no-app-view rule, and the studio-config requirement all\n// live here next to `federation` — the build package just hands over its inputs.\n\nimport path from 'node:path'\n\nimport {readPackageJson} from '@sanity/cli-core'\nimport {type PluginOption} from 'vite'\n\nimport {type WorkbenchExposes} from '../../../resolveWorkbenchApp.js'\nimport {federation} from './plugin.js'\nimport {sanityAppId} from './plugins/plugin-sanity-app-id.js'\n\ninterface WorkbenchViteOptions {\n /** Project root — read for the federation remote name, and the plugin workDir. */\n cwd: string\n /**\n * Build entry paths relative to the federation runtime dir. `relativeEntry` is\n * the app's `entry` (null for a dock-only app with no app view);\n * `relativeConfigLocation` is the studio's `sanity.config.*` (null when absent).\n */\n entries: {relativeConfigLocation: string | null; relativeEntry: string | null}\n\n /** The app's bus identity, stamped into its modules for `@sanity/runtime`. */\n appId?: string\n\n exposes?: WorkbenchExposes\n /** App (vs studio) build — selects the discriminated federation option shape. */\n isApp?: boolean\n /** Blueprints build (via `@sanity/runtime-cli`) — emit the resource-bindings module. */\n isBlueprints?: boolean\n}\n\n/**\n * A workbench studio renders from its `sanity.config.*`, so the build needs one.\n * An explicit `applicationType: 'studio'` wins over detection, so a studio can\n * reach here with no config file — fail with the fix rather than a cryptic build\n * error downstream.\n */\nfunction requireStudioConfigPath(relativeConfigLocation: string | null): string {\n if (relativeConfigLocation === null) {\n throw new Error(\n 'Workbench studios need a sanity.config.js or sanity.config.ts file. ' +\n \"Add one, or remove `applicationType: 'studio'` from `defineApplication` \" +\n 'to let the CLI infer the application type.',\n )\n }\n return relativeConfigLocation\n}\n\n/** Build the Vite plugins for a workbench app's module-federation remote. */\nexport async function workbenchVitePlugins(options: WorkbenchViteOptions): Promise<PluginOption> {\n const {appId, cwd, entries, exposes, isApp, isBlueprints} = options\n const pkgJson = await readPackageJson(path.join(cwd, 'package.json'))\n\n const federationPlugin = federation({\n ...(isApp\n ? {\n // `null` relativeEntry (a branded app with no `entry`) → omit `appEntry`,\n // so the remote exposes no `./App`, only its views.\n ...(entries.relativeEntry ? {appEntry: entries.relativeEntry} : {}),\n isApp: true as const,\n }\n : {\n isApp: false as const,\n studioConfigPath: requireStudioConfigPath(entries.relativeConfigLocation),\n }),\n exposes,\n isBlueprints,\n pkgJson,\n workDir: cwd,\n })\n\n return appId === undefined ? federationPlugin : [federationPlugin, sanityAppId(appId)]\n}\n"],"names":["path","readPackageJson","federation","sanityAppId","requireStudioConfigPath","relativeConfigLocation","Error","workbenchVitePlugins","options","appId","cwd","entries","exposes","isApp","isBlueprints","pkgJson","join","federationPlugin","relativeEntry","appEntry","studioConfigPath","workDir","undefined"],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,sEAAsE;AACtE,+EAA+E;AAC/E,4EAA4E;AAC5E,iFAAiF;AAEjF,OAAOA,UAAU,YAAW;AAE5B,SAAQC,eAAe,QAAO,mBAAkB;AAIhD,SAAQC,UAAU,QAAO,cAAa;AACtC,SAAQC,WAAW,QAAO,oCAAmC;AAsB7D;;;;;CAKC,GACD,SAASC,wBAAwBC,sBAAqC;IACpE,IAAIA,2BAA2B,MAAM;QACnC,MAAM,IAAIC,MACR,yEACE,6EACA;IAEN;IACA,OAAOD;AACT;AAEA,2EAA2E,GAC3E,OAAO,eAAeE,qBAAqBC,OAA6B;IACtE,MAAM,EAACC,KAAK,EAAEC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,KAAK,EAAEC,YAAY,EAAC,GAAGN;IAC5D,MAAMO,UAAU,MAAMd,gBAAgBD,KAAKgB,IAAI,CAACN,KAAK;IAErD,MAAMO,mBAAmBf,WAAW;QAClC,GAAIW,QACA;YACE,0EAA0E;YAC1E,oDAAoD;YACpD,GAAIF,QAAQO,aAAa,GAAG;gBAACC,UAAUR,QAAQO,aAAa;YAAA,IAAI,CAAC,CAAC;YAClEL,OAAO;QACT,IACA;YACEA,OAAO;YACPO,kBAAkBhB,wBAAwBO,QAAQN,sBAAsB;QAC1E,CAAC;QACLO;QACAE;QACAC;QACAM,SAASX;IACX;IAEA,OAAOD,UAAUa,YAAYL,mBAAmB;QAACA;QAAkBd,YAAYM;KAAO;AACxF"}
@@ -2,7 +2,7 @@ import { basename, dirname } from 'node:path';
2
2
  import { styleText } from 'node:util';
3
3
  import { createGzip } from 'node:zlib';
4
4
  import { subdebug } from '@sanity/cli-core';
5
- import { pack } from 'tar-fs';
5
+ import { c as createTar } from 'tar';
6
6
  import { getWorkbenchUrl } from '../../services/applications.js';
7
7
  import { createConfig, resolveSingletonInstallationId } from '../../services/installations.js';
8
8
  import { summarizeGroup } from './summarizeInterfaces.js';
@@ -46,11 +46,11 @@ const debug = subdebug('deploy');
46
46
  * @internal
47
47
  */ export async function deployConfig(options) {
48
48
  const { appType, installationId, organizationId, output, sourceDir, version } = options;
49
- const tarball = pack(dirname(sourceDir), {
50
- entries: [
51
- basename(sourceDir)
52
- ]
53
- }).pipe(createGzip());
49
+ const tarball = createTar({
50
+ cwd: dirname(sourceDir)
51
+ }, [
52
+ basename(sourceDir)
53
+ ]).pipe(createGzip());
54
54
  await createConfig(installationId, {
55
55
  tarball,
56
56
  version
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployConfig.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {type Output, subdebug} from '@sanity/cli-core'\nimport {pack} from 'tar-fs'\n\nimport {getWorkbenchUrl} from '../../services/applications.js'\nimport {createConfig, resolveSingletonInstallationId} from '../../services/installations.js'\nimport {summarizeGroup} from './summarizeInterfaces.js'\n\nconst debug = subdebug('deploy')\n\n/**\n * The org's active installation for an app type, or `undefined` when none is\n * installed. Read-only, so `--dry-run` can report deployability.\n * @internal\n */\nexport async function resolveInstallationId(options: {\n appType: string\n organizationId: string\n}): Promise<string | undefined> {\n switch (options.appType) {\n case 'media-library': {\n return resolveSingletonInstallationId(options.organizationId, 'media-library')\n }\n default: {\n throw new Error(`Cannot create config for unknown app type: ${options.appType}`)\n }\n }\n}\n\n/**\n * A report heading and item list for a config; a media library's `fields` are\n * one of potentially many shapes.\n * @internal\n */\nexport function summarizeConfig(config: {\n appType: string\n fields: {name: string; src: string; title: string}[]\n}): string {\n switch (config.appType) {\n case 'media-library': {\n return summarizeGroup('Media library fields', config.fields)\n }\n default: {\n throw new Error(`Cannot create config for unknown app type: ${config.appType}`)\n }\n }\n}\n\n/**\n * Upload the built module-federation remote to the installation as its config\n * snapshot. `installationId` is resolved by the caller so `--dry-run` never\n * reaches this mutating step.\n * @internal\n */\nexport async function deployConfig(options: {\n appType: string\n installationId: string\n organizationId: string\n output: Output\n sourceDir: string\n version: string\n}): Promise<void> {\n const {appType, installationId, organizationId, output, sourceDir, version} = options\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n await createConfig(installationId, {tarball, version})\n\n debug('Deployed config for app type: %s', appType)\n const url = getWorkbenchUrl(organizationId)\n output.log(`\\n🚀 ${styleText('bold', 'Success!')} Config deployed to ${styleText('cyan', url)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","subdebug","pack","getWorkbenchUrl","createConfig","resolveSingletonInstallationId","summarizeGroup","debug","resolveInstallationId","options","appType","organizationId","Error","summarizeConfig","config","fields","deployConfig","installationId","output","sourceDir","version","tarball","entries","pipe","url","log"],"mappings":"AAAA,SAAQA,QAAQ,EAAEC,OAAO,QAAO,YAAW;AAC3C,SAAQC,SAAS,QAAO,YAAW;AACnC,SAAQC,UAAU,QAAO,YAAW;AAEpC,SAAqBC,QAAQ,QAAO,mBAAkB;AACtD,SAAQC,IAAI,QAAO,SAAQ;AAE3B,SAAQC,eAAe,QAAO,iCAAgC;AAC9D,SAAQC,YAAY,EAAEC,8BAA8B,QAAO,kCAAiC;AAC5F,SAAQC,cAAc,QAAO,2BAA0B;AAEvD,MAAMC,QAAQN,SAAS;AAEvB;;;;CAIC,GACD,OAAO,eAAeO,sBAAsBC,OAG3C;IACC,OAAQA,QAAQC,OAAO;QACrB,KAAK;YAAiB;gBACpB,OAAOL,+BAA+BI,QAAQE,cAAc,EAAE;YAChE;QACA;YAAS;gBACP,MAAM,IAAIC,MAAM,CAAC,2CAA2C,EAAEH,QAAQC,OAAO,EAAE;YACjF;IACF;AACF;AAEA;;;;CAIC,GACD,OAAO,SAASG,gBAAgBC,MAG/B;IACC,OAAQA,OAAOJ,OAAO;QACpB,KAAK;YAAiB;gBACpB,OAAOJ,eAAe,wBAAwBQ,OAAOC,MAAM;YAC7D;QACA;YAAS;gBACP,MAAM,IAAIH,MAAM,CAAC,2CAA2C,EAAEE,OAAOJ,OAAO,EAAE;YAChF;IACF;AACF;AAEA;;;;;CAKC,GACD,OAAO,eAAeM,aAAaP,OAOlC;IACC,MAAM,EAACC,OAAO,EAAEO,cAAc,EAAEN,cAAc,EAAEO,MAAM,EAAEC,SAAS,EAAEC,OAAO,EAAC,GAAGX;IAC9E,MAAMY,UAAUnB,KAAKJ,QAAQqB,YAAY;QAACG,SAAS;YAACzB,SAASsB;SAAW;IAAA,GAAGI,IAAI,CAACvB;IAChF,MAAMI,aAAaa,gBAAgB;QAACI;QAASD;IAAO;IAEpDb,MAAM,oCAAoCG;IAC1C,MAAMc,MAAMrB,gBAAgBQ;IAC5BO,OAAOO,GAAG,CAAC,CAAC,KAAK,EAAE1B,UAAU,QAAQ,YAAY,oBAAoB,EAAEA,UAAU,QAAQyB,MAAM;AACjG"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployConfig.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {type Output, subdebug} from '@sanity/cli-core'\nimport {c as createTar} from 'tar'\n\nimport {getWorkbenchUrl} from '../../services/applications.js'\nimport {createConfig, resolveSingletonInstallationId} from '../../services/installations.js'\nimport {summarizeGroup} from './summarizeInterfaces.js'\n\nconst debug = subdebug('deploy')\n\n/**\n * The org's active installation for an app type, or `undefined` when none is\n * installed. Read-only, so `--dry-run` can report deployability.\n * @internal\n */\nexport async function resolveInstallationId(options: {\n appType: string\n organizationId: string\n}): Promise<string | undefined> {\n switch (options.appType) {\n case 'media-library': {\n return resolveSingletonInstallationId(options.organizationId, 'media-library')\n }\n default: {\n throw new Error(`Cannot create config for unknown app type: ${options.appType}`)\n }\n }\n}\n\n/**\n * A report heading and item list for a config; a media library's `fields` are\n * one of potentially many shapes.\n * @internal\n */\nexport function summarizeConfig(config: {\n appType: string\n fields: {name: string; src: string; title: string}[]\n}): string {\n switch (config.appType) {\n case 'media-library': {\n return summarizeGroup('Media library fields', config.fields)\n }\n default: {\n throw new Error(`Cannot create config for unknown app type: ${config.appType}`)\n }\n }\n}\n\n/**\n * Upload the built module-federation remote to the installation as its config\n * snapshot. `installationId` is resolved by the caller so `--dry-run` never\n * reaches this mutating step.\n * @internal\n */\nexport async function deployConfig(options: {\n appType: string\n installationId: string\n organizationId: string\n output: Output\n sourceDir: string\n version: string\n}): Promise<void> {\n const {appType, installationId, organizationId, output, sourceDir, version} = options\n const tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n await createConfig(installationId, {tarball, version})\n\n debug('Deployed config for app type: %s', appType)\n const url = getWorkbenchUrl(organizationId)\n output.log(`\\n🚀 ${styleText('bold', 'Success!')} Config deployed to ${styleText('cyan', url)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","subdebug","c","createTar","getWorkbenchUrl","createConfig","resolveSingletonInstallationId","summarizeGroup","debug","resolveInstallationId","options","appType","organizationId","Error","summarizeConfig","config","fields","deployConfig","installationId","output","sourceDir","version","tarball","cwd","pipe","url","log"],"mappings":"AAAA,SAAQA,QAAQ,EAAEC,OAAO,QAAO,YAAW;AAC3C,SAAQC,SAAS,QAAO,YAAW;AACnC,SAAQC,UAAU,QAAO,YAAW;AAEpC,SAAqBC,QAAQ,QAAO,mBAAkB;AACtD,SAAQC,KAAKC,SAAS,QAAO,MAAK;AAElC,SAAQC,eAAe,QAAO,iCAAgC;AAC9D,SAAQC,YAAY,EAAEC,8BAA8B,QAAO,kCAAiC;AAC5F,SAAQC,cAAc,QAAO,2BAA0B;AAEvD,MAAMC,QAAQP,SAAS;AAEvB;;;;CAIC,GACD,OAAO,eAAeQ,sBAAsBC,OAG3C;IACC,OAAQA,QAAQC,OAAO;QACrB,KAAK;YAAiB;gBACpB,OAAOL,+BAA+BI,QAAQE,cAAc,EAAE;YAChE;QACA;YAAS;gBACP,MAAM,IAAIC,MAAM,CAAC,2CAA2C,EAAEH,QAAQC,OAAO,EAAE;YACjF;IACF;AACF;AAEA;;;;CAIC,GACD,OAAO,SAASG,gBAAgBC,MAG/B;IACC,OAAQA,OAAOJ,OAAO;QACpB,KAAK;YAAiB;gBACpB,OAAOJ,eAAe,wBAAwBQ,OAAOC,MAAM;YAC7D;QACA;YAAS;gBACP,MAAM,IAAIH,MAAM,CAAC,2CAA2C,EAAEE,OAAOJ,OAAO,EAAE;YAChF;IACF;AACF;AAEA;;;;;CAKC,GACD,OAAO,eAAeM,aAAaP,OAOlC;IACC,MAAM,EAACC,OAAO,EAAEO,cAAc,EAAEN,cAAc,EAAEO,MAAM,EAAEC,SAAS,EAAEC,OAAO,EAAC,GAAGX;IAC9E,MAAMY,UAAUnB,UAAU;QAACoB,KAAKzB,QAAQsB;IAAU,GAAG;QAACvB,SAASuB;KAAW,EAAEI,IAAI,CAACxB;IACjF,MAAMK,aAAaa,gBAAgB;QAACI;QAASD;IAAO;IAEpDb,MAAM,oCAAoCG;IAC1C,MAAMc,MAAMrB,gBAAgBQ;IAC5BO,OAAOO,GAAG,CAAC,CAAC,KAAK,EAAE3B,UAAU,QAAQ,YAAY,oBAAoB,EAAEA,UAAU,QAAQ0B,MAAM;AACjG"}
@@ -1,7 +1,7 @@
1
1
  import { basename, dirname } from 'node:path';
2
2
  import { createGzip } from 'node:zlib';
3
3
  import { spinner } from '@sanity/cli-core/ux';
4
- import { pack } from 'tar-fs';
4
+ import { c as createTar } from 'tar';
5
5
  import { deriveInterfaces } from '../../deriveInterfaces.js';
6
6
  import { createApplication, createDeployment, deleteApplication, updateApplication } from '../../services/applications.js';
7
7
  function toBrettInterface(iface, version) {
@@ -102,11 +102,11 @@ function toBrettInterface(iface, version) {
102
102
  * @internal
103
103
  */ export async function deployWorkbenchApp(options) {
104
104
  const { access, app, applicationId, icon, isApp, isAutoUpdating, label = 'Deploying...', onDeployed, sourceDir, title, version, visibility, workspaces } = options;
105
- const tarball = pack(dirname(sourceDir), {
106
- entries: [
107
- basename(sourceDir)
108
- ]
109
- }).pipe(createGzip());
105
+ const tarball = createTar({
106
+ cwd: dirname(sourceDir)
107
+ }, [
108
+ basename(sourceDir)
109
+ ]).pipe(createGzip());
110
110
  const spin = spinner(label).start();
111
111
  try {
112
112
  await createDeployment({
@@ -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 '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 case 'window': {\n const {surface, ...view} = declaration\n return {...view, type: 'app', 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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"}
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 {c as createTar} from 'tar'\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 '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 case 'window': {\n const {surface, ...view} = declaration\n return {...view, type: 'app', 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 = createTar({cwd: dirname(sourceDir)}, [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","c","createTar","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","cwd","pipe","interfaces","appTitle","map","clear"],"mappings":"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"}
@@ -17,14 +17,16 @@ const noop = async ()=>{};
17
17
  // with no interfaces (the media library). A server with both lands in both channels.
18
18
  const isLocalApp = (server)=>!isConfigOnlyServer(server);
19
19
  const toApplicationsPayload = (servers)=>({
20
- applications: servers.filter((server)=>isLocalApp(server)).map(({ host, id, interfaces, manifest, port, projectId, type })=>({
20
+ applications: servers.filter((server)=>isLocalApp(server)).map(({ host, id, interfaces, manifest, name, port, projectId, reference, type })=>({
21
21
  host,
22
22
  id,
23
23
  // Views cross to the remote keyed on `type`, never the internal `surface`.
24
24
  interfaces: interfaces?.map((iface)=>toWireInterface(iface)),
25
25
  manifest,
26
+ name,
26
27
  port,
27
28
  projectId,
29
+ reference,
28
30
  type
29
31
  })),
30
32
  configs: servers.flatMap(({ configs, host, port })=>// The registry stores the config flat; the workbench wire shape nests the
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/dev/startWorkbenchDevServer.ts"],"sourcesContent":["import {fileURLToPath} from 'node:url'\n\nimport {type CliConfig, type Output, subdebug} from '@sanity/cli-core'\nimport {isStaging} from '@sanity/cli-core/util'\nimport viteReact from '@vitejs/plugin-react'\nimport {createServer, type InlineConfig, type Plugin, type ViteDevServer} from 'vite'\nimport {z} from 'zod/mini'\n\nimport {isWorkbenchApp, isWorkbenchConfig} from '../../defineApp.js'\nimport {createExposesTracker} from './exposesSetId.js'\nimport {\n acquireWorkbenchLock,\n type DevServerManifest,\n getRegisteredServers,\n isConfigOnlyServer,\n readWorkbenchLock,\n watchRegistry,\n} from './registry.js'\nimport {toWireInterface} from './toWireInterface.js'\nimport {writeWorkbenchRuntime} from './writeWorkbenchRuntime.js'\n\nconst devDebug = subdebug('dev')\nconst renderDashboardEntry = '@sanity/workbench-cli/_internal_render'\nconst renderDashboardPath = fileURLToPath(\n new URL('../../_exports/_internal_render.js', import.meta.url),\n)\n\nconst noop = async () => {}\n\n// Every server is a local app except a config-only one — a config\n// with no interfaces (the media library). A server with both lands in both channels.\nconst isLocalApp = (server: DevServerManifest): boolean => !isConfigOnlyServer(server)\n\nconst toApplicationsPayload = (servers: DevServerManifest[]) => ({\n applications: servers\n .filter((server) => isLocalApp(server))\n .map(({host, id, interfaces, manifest, port, projectId, type}) => ({\n host,\n id,\n // Views cross to the remote keyed on `type`, never the internal `surface`.\n interfaces: interfaces?.map((iface) => toWireInterface(iface)),\n manifest,\n port,\n projectId,\n type,\n })),\n configs: servers.flatMap(({configs, host, port}) =>\n // The registry stores the config flat; the workbench wire shape nests the\n // type-specific payload (`fields` for a media library) under `config`, keyed\n // by the `appType` discriminator.\n (configs ?? []).map(({appType, id, moduleName, version, ...config}) => ({\n appType,\n config,\n id,\n moduleName,\n remoteURL: `http://${host}:${port}`,\n version,\n })),\n ),\n})\n\n/**\n * Bridge the dev-server registry into a workbench Vite server's HMR channel so\n * the page tracks apps as they come and go. A changed interface set means a\n * rebuilt remote — full-reload to drop the stale remote-entry; otherwise\n * rebroadcast for a soft reconcile. Returns a detach fn.\n */\nfunction attachViteDevServerBridge(server: ViteDevServer): () => void {\n server.ws.on('sanity:workbench:get-local-applications', (_, client) => {\n client.send(\n 'sanity:workbench:local-applications',\n toApplicationsPayload(getRegisteredServers()),\n )\n })\n\n const setTracker = createExposesTracker()\n const registryWatcher = watchRegistry((servers) => {\n if (setTracker.hasChanged(servers)) {\n server.ws.send({type: 'full-reload'})\n return\n }\n server.ws.send('sanity:workbench:local-applications', toApplicationsPayload(servers))\n })\n\n return () => registryWatcher.close()\n}\n\n/**\n * Make the workbench remote act as the machine's workbench: claim the singleton\n * lock so app `sanity dev`s register into it instead of each starting their own,\n * and bridge the registry so the remote shows the local apps. No-op lock if one\n * is already held.\n */\nexport function startWorkbenchRemoteCoordinator(options: {\n httpHost: string | undefined\n port: number\n server: ViteDevServer\n}): {close: () => Promise<void>} {\n const {httpHost, port, server} = options\n\n const lock = acquireWorkbenchLock({host: httpHost || 'localhost', port})\n if (!lock) {\n const existing = readWorkbenchLock()\n devDebug(\n 'Workbench lock already held by pid %d on port %d; bridging the registry without claiming it',\n existing?.pid,\n existing?.port,\n )\n }\n\n const detachBridge = attachViteDevServerBridge(server)\n\n return {\n close: async () => {\n detachBridge()\n lock?.release()\n },\n }\n}\n\ninterface WorkbenchDevServerResult {\n close: () => Promise<void>\n httpHost: string | undefined\n workbenchAvailable: boolean\n workbenchPort: number\n}\n\nexport interface StartWorkbenchOptions {\n /** Dependency-cache dir for the workbench Vite server, kept apart from the user's own. */\n cacheDir: string\n cliConfig: CliConfig\n httpHost: string | undefined\n httpPort: number\n /** `dev` renders a live app and honors a local workbench-UI override; `preview`\n * (`sanity start`) previews a build and loads the deployed workbench UI. */\n mode: 'development' | 'preview'\n output: Output\n /** Wrap the workbench in React StrictMode; the CLI resolves it (unset collapses to `false`). */\n reactStrictMode: boolean\n workDir: string\n}\n\nexport async function startWorkbenchDevServer(\n options: StartWorkbenchOptions,\n): Promise<WorkbenchDevServerResult> {\n const {\n cacheDir,\n cliConfig,\n httpHost,\n httpPort: workbenchPort,\n mode,\n output,\n reactStrictMode,\n workDir,\n } = options\n\n // Workbench is opted into by a `defineApplication` app or a config-only\n // `unstable_defineMediaLibrary` config — the latter still needs the shell to\n // render it.\n if (!isWorkbenchApp(cliConfig?.app) && !isWorkbenchConfig(cliConfig?.app)) {\n devDebug('Not a workbench app or config, skipping workbench dev server')\n return {close: noop, httpHost, workbenchAvailable: false, workbenchPort}\n }\n\n // Acquire an exclusive lock — only one workbench per machine.\n // Uses O_EXCL which is atomic at the OS level, preventing races when\n // multiple `sanity dev` processes start simultaneously (e.g. via turbo).\n const workbenchLock = acquireWorkbenchLock({host: httpHost || 'localhost', port: workbenchPort})\n if (!workbenchLock) {\n const existing = readWorkbenchLock()\n devDebug(\n 'Workbench already running at pid %d on port %d, skipping',\n existing?.pid,\n existing?.port,\n )\n return {\n close: noop,\n httpHost: existing?.host ?? httpHost,\n workbenchAvailable: true,\n workbenchPort: existing?.port ?? workbenchPort,\n }\n }\n\n // The lock is already held; an exception here (runtime-file write failure,\n // invalid remote URL) would otherwise leak it until the next acquire prunes\n // the stale PID.\n let result: Awaited<ReturnType<typeof createWorkbenchViteServer>>\n try {\n result = await createWorkbenchViteServer({\n cacheDir,\n cliConfig,\n httpHost,\n mode,\n output,\n reactStrictMode,\n workbenchPort,\n workDir,\n })\n } catch (err) {\n workbenchLock.release()\n throw err\n }\n\n if (!result) {\n workbenchLock.release()\n return {close: noop, httpHost, workbenchAvailable: false, workbenchPort}\n }\n\n const {actualPort, close} = result\n workbenchLock.updatePort(actualPort)\n\n return {\n close: async () => {\n workbenchLock.release()\n await close()\n },\n httpHost,\n workbenchAvailable: true,\n workbenchPort: actualPort,\n }\n}\n\ninterface CreateWorkbenchViteServerOptions {\n cacheDir: string\n cliConfig: CliConfig\n httpHost: string | undefined\n mode: 'development' | 'preview'\n output: Output\n reactStrictMode: boolean\n workbenchPort: number\n workDir: string\n}\n\ninterface CreateWorkbenchViteServerResult {\n actualPort: number\n close: () => Promise<void>\n}\n\nasync function createWorkbenchViteServer(\n options: CreateWorkbenchViteServerOptions,\n): Promise<CreateWorkbenchViteServerResult | undefined> {\n const {cacheDir, cliConfig, httpHost, mode, output, reactStrictMode, workbenchPort, workDir} =\n options\n\n // `preview` loads `.env.development` (the env hook treats only `build`/`deploy`\n // as production), which points the workbench UI at a local dev server that\n // isn't running here. Ignore the override and load the deployed UI instead.\n const remoteUrl =\n mode === 'preview'\n ? undefined\n : parseRemoteUrl(process.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL)\n\n const organizationId = resolveOrganizationId(cliConfig)\n\n devDebug('Writing workbench runtime files')\n const root = await writeWorkbenchRuntime({\n cwd: workDir,\n organizationId,\n reactStrictMode,\n remoteUrl,\n })\n\n const viteConfig: InlineConfig = {\n // Custom cache directory so sanity's vite cache doesn't conflict with local vite projects\n cacheDir,\n configFile: false,\n define: {\n __SANITY_STAGING__: isStaging(),\n 'import.meta.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL': JSON.stringify(remoteUrl),\n },\n logLevel: 'warn',\n mode: 'development',\n optimizeDeps: {\n // Keep this entry out of pre-bundling so Vite injects its HMR context.\n exclude: [renderDashboardEntry],\n },\n // viteReact looks inert here — it transforms none of the host's own modules —\n // but it's load-bearing for the remotes. It serves the Fast Refresh runtime at\n // /@react-refresh and injects the preamble that defines window.$RefreshReg$. The\n // federated remotes loaded into this page are react-refresh transformed, so\n // without the preamble they throw \"can't detect preamble\", and without the\n // runtime their /@react-refresh import (wired by @module-federation/vite's\n // remoteHmr) fails. Dropping it as dead code broke every panel; see #1262.\n plugins: [viteReact(), ...(remoteUrl ? [remoteManifestPreloadHeaderPlugin(remoteUrl)] : [])],\n resolve: {\n // The generated Vite root cannot reliably resolve this package.\n alias: {[renderDashboardEntry]: renderDashboardPath},\n dedupe: ['react', 'react-dom'],\n },\n root,\n server: {\n host: httpHost,\n port: workbenchPort,\n strictPort: false,\n warmup: {\n clientFiles: ['./workbench.js'],\n },\n },\n }\n\n devDebug('Creating workbench vite server')\n const server = await createServer(viteConfig)\n try {\n await server.listen()\n } catch (err) {\n await server.close()\n output.warn(\n `Workbench dev server failed to start: ${err instanceof Error ? err.message : String(err)}`,\n )\n return undefined\n }\n\n // Vite may have picked a different port if the desired one was occupied\n const addr = server.httpServer?.address()\n const actualPort = typeof addr === 'object' && addr ? addr.port : workbenchPort\n\n // Fire-and-forget: warm the workbench remote's Vite transform pipeline so\n // the first browser request hits a pre-populated module graph.\n if (remoteUrl) {\n fetch(remoteUrl)\n .then((r) => r.body?.cancel())\n .catch(() => {})\n devDebug('Warming workbench remote at %s', remoteUrl)\n }\n\n const detachBridge = attachViteDevServerBridge(server)\n\n return {\n actualPort,\n close: async () => {\n detachBridge()\n await server.close()\n },\n }\n}\n\n// Workbench is opted into via `defineApplication`, which carries the\n// organization ID. Deliberately no fallback (e.g. resolving it from the\n// configured project): the lookup would need an authenticated user and an\n// API round-trip on every startup for something the opt-in already declares.\nconst resolveOrganizationId = (cliConfig: CliConfig): string => {\n if (cliConfig.app?.organizationId) {\n return cliConfig.app.organizationId\n }\n\n throw new Error(\n 'Workbench requires an organization ID. Pass \"organizationId\" to defineApplication() in sanity.cli.ts.',\n )\n}\n\n// Restricts protocol to http(s) so the URL is safe to interpolate into HTML\n// attributes and Link headers downstream.\nconst remoteUrlSchema = z.url({normalize: true, protocol: /^https?$/})\n\nfunction parseRemoteUrl(value: string | undefined): string | undefined {\n if (!value) return undefined\n\n const result = remoteUrlSchema.safeParse(value)\n\n if (!result.success) {\n throw new Error(\n `Invalid SANITY_INTERNAL_WORKBENCH_REMOTE_URL: ${value} (must be an http(s) URL)`,\n )\n }\n\n return result.data\n}\n\n/**\n * Sets a `Link: <remoteUrl>; rel=preload; as=fetch; crossorigin` response header\n * on the index document so the browser can start fetching the Module Federation\n * manifest as soon as response headers arrive — before HTML parsing reaches the\n * in-head preconnect hint. `as=fetch` matches how the federation runtime later\n * retrieves the JSON manifest, allowing the preload entry to satisfy that fetch.\n */\nfunction remoteManifestPreloadHeaderPlugin(remoteUrl: string): Plugin {\n return {\n apply: 'serve',\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const pathname = (req.url || '/').split('?')[0]\n if (pathname === '/' || pathname === '/index.html') {\n res.setHeader('Link', `<${remoteUrl}>; rel=preload; as=fetch; crossorigin`)\n }\n next()\n })\n },\n name: 'sanity:workbench-remote-preload-header',\n }\n}\n"],"names":["fileURLToPath","subdebug","isStaging","viteReact","createServer","z","isWorkbenchApp","isWorkbenchConfig","createExposesTracker","acquireWorkbenchLock","getRegisteredServers","isConfigOnlyServer","readWorkbenchLock","watchRegistry","toWireInterface","writeWorkbenchRuntime","devDebug","renderDashboardEntry","renderDashboardPath","URL","url","noop","isLocalApp","server","toApplicationsPayload","servers","applications","filter","map","host","id","interfaces","manifest","port","projectId","type","iface","configs","flatMap","appType","moduleName","version","config","remoteURL","attachViteDevServerBridge","ws","on","_","client","send","setTracker","registryWatcher","hasChanged","close","startWorkbenchRemoteCoordinator","options","httpHost","lock","existing","pid","detachBridge","release","startWorkbenchDevServer","cacheDir","cliConfig","httpPort","workbenchPort","mode","output","reactStrictMode","workDir","app","workbenchAvailable","workbenchLock","result","createWorkbenchViteServer","err","actualPort","updatePort","remoteUrl","undefined","parseRemoteUrl","process","env","SANITY_INTERNAL_WORKBENCH_REMOTE_URL","organizationId","resolveOrganizationId","root","cwd","viteConfig","configFile","define","__SANITY_STAGING__","JSON","stringify","logLevel","optimizeDeps","exclude","plugins","remoteManifestPreloadHeaderPlugin","resolve","alias","dedupe","strictPort","warmup","clientFiles","listen","warn","Error","message","String","addr","httpServer","address","fetch","then","r","body","cancel","catch","remoteUrlSchema","normalize","protocol","value","safeParse","success","data","apply","configureServer","middlewares","use","req","res","next","pathname","split","setHeader","name"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/dev/startWorkbenchDevServer.ts"],"sourcesContent":["import {fileURLToPath} from 'node:url'\n\nimport {type CliConfig, type Output, subdebug} from '@sanity/cli-core'\nimport {isStaging} from '@sanity/cli-core/util'\nimport viteReact from '@vitejs/plugin-react'\nimport {createServer, type InlineConfig, type Plugin, type ViteDevServer} from 'vite'\nimport {z} from 'zod/mini'\n\nimport {isWorkbenchApp, isWorkbenchConfig} from '../../defineApp.js'\nimport {createExposesTracker} from './exposesSetId.js'\nimport {\n acquireWorkbenchLock,\n type DevServerManifest,\n getRegisteredServers,\n isConfigOnlyServer,\n readWorkbenchLock,\n watchRegistry,\n} from './registry.js'\nimport {toWireInterface} from './toWireInterface.js'\nimport {writeWorkbenchRuntime} from './writeWorkbenchRuntime.js'\n\nconst devDebug = subdebug('dev')\nconst renderDashboardEntry = '@sanity/workbench-cli/_internal_render'\nconst renderDashboardPath = fileURLToPath(\n new URL('../../_exports/_internal_render.js', import.meta.url),\n)\n\nconst noop = async () => {}\n\n// Every server is a local app except a config-only one — a config\n// with no interfaces (the media library). A server with both lands in both channels.\nconst isLocalApp = (server: DevServerManifest): boolean => !isConfigOnlyServer(server)\n\nconst toApplicationsPayload = (servers: DevServerManifest[]) => ({\n applications: servers\n .filter((server) => isLocalApp(server))\n .map(({host, id, interfaces, manifest, name, port, projectId, reference, type}) => ({\n host,\n id,\n // Views cross to the remote keyed on `type`, never the internal `surface`.\n interfaces: interfaces?.map((iface) => toWireInterface(iface)),\n manifest,\n name,\n port,\n projectId,\n reference,\n type,\n })),\n configs: servers.flatMap(({configs, host, port}) =>\n // The registry stores the config flat; the workbench wire shape nests the\n // type-specific payload (`fields` for a media library) under `config`, keyed\n // by the `appType` discriminator.\n (configs ?? []).map(({appType, id, moduleName, version, ...config}) => ({\n appType,\n config,\n id,\n moduleName,\n remoteURL: `http://${host}:${port}`,\n version,\n })),\n ),\n})\n\n/**\n * Bridge the dev-server registry into a workbench Vite server's HMR channel so\n * the page tracks apps as they come and go. A changed interface set means a\n * rebuilt remote — full-reload to drop the stale remote-entry; otherwise\n * rebroadcast for a soft reconcile. Returns a detach fn.\n */\nfunction attachViteDevServerBridge(server: ViteDevServer): () => void {\n server.ws.on('sanity:workbench:get-local-applications', (_, client) => {\n client.send(\n 'sanity:workbench:local-applications',\n toApplicationsPayload(getRegisteredServers()),\n )\n })\n\n const setTracker = createExposesTracker()\n const registryWatcher = watchRegistry((servers) => {\n if (setTracker.hasChanged(servers)) {\n server.ws.send({type: 'full-reload'})\n return\n }\n server.ws.send('sanity:workbench:local-applications', toApplicationsPayload(servers))\n })\n\n return () => registryWatcher.close()\n}\n\n/**\n * Make the workbench remote act as the machine's workbench: claim the singleton\n * lock so app `sanity dev`s register into it instead of each starting their own,\n * and bridge the registry so the remote shows the local apps. No-op lock if one\n * is already held.\n */\nexport function startWorkbenchRemoteCoordinator(options: {\n httpHost: string | undefined\n port: number\n server: ViteDevServer\n}): {close: () => Promise<void>} {\n const {httpHost, port, server} = options\n\n const lock = acquireWorkbenchLock({host: httpHost || 'localhost', port})\n if (!lock) {\n const existing = readWorkbenchLock()\n devDebug(\n 'Workbench lock already held by pid %d on port %d; bridging the registry without claiming it',\n existing?.pid,\n existing?.port,\n )\n }\n\n const detachBridge = attachViteDevServerBridge(server)\n\n return {\n close: async () => {\n detachBridge()\n lock?.release()\n },\n }\n}\n\ninterface WorkbenchDevServerResult {\n close: () => Promise<void>\n httpHost: string | undefined\n workbenchAvailable: boolean\n workbenchPort: number\n}\n\nexport interface StartWorkbenchOptions {\n /** Dependency-cache dir for the workbench Vite server, kept apart from the user's own. */\n cacheDir: string\n cliConfig: CliConfig\n httpHost: string | undefined\n httpPort: number\n /** `dev` renders a live app and honors a local workbench-UI override; `preview`\n * (`sanity start`) previews a build and loads the deployed workbench UI. */\n mode: 'development' | 'preview'\n output: Output\n /** Wrap the workbench in React StrictMode; the CLI resolves it (unset collapses to `false`). */\n reactStrictMode: boolean\n workDir: string\n}\n\nexport async function startWorkbenchDevServer(\n options: StartWorkbenchOptions,\n): Promise<WorkbenchDevServerResult> {\n const {\n cacheDir,\n cliConfig,\n httpHost,\n httpPort: workbenchPort,\n mode,\n output,\n reactStrictMode,\n workDir,\n } = options\n\n // Workbench is opted into by a `defineApplication` app or a config-only\n // `unstable_defineMediaLibrary` config — the latter still needs the shell to\n // render it.\n if (!isWorkbenchApp(cliConfig?.app) && !isWorkbenchConfig(cliConfig?.app)) {\n devDebug('Not a workbench app or config, skipping workbench dev server')\n return {close: noop, httpHost, workbenchAvailable: false, workbenchPort}\n }\n\n // Acquire an exclusive lock — only one workbench per machine.\n // Uses O_EXCL which is atomic at the OS level, preventing races when\n // multiple `sanity dev` processes start simultaneously (e.g. via turbo).\n const workbenchLock = acquireWorkbenchLock({host: httpHost || 'localhost', port: workbenchPort})\n if (!workbenchLock) {\n const existing = readWorkbenchLock()\n devDebug(\n 'Workbench already running at pid %d on port %d, skipping',\n existing?.pid,\n existing?.port,\n )\n return {\n close: noop,\n httpHost: existing?.host ?? httpHost,\n workbenchAvailable: true,\n workbenchPort: existing?.port ?? workbenchPort,\n }\n }\n\n // The lock is already held; an exception here (runtime-file write failure,\n // invalid remote URL) would otherwise leak it until the next acquire prunes\n // the stale PID.\n let result: Awaited<ReturnType<typeof createWorkbenchViteServer>>\n try {\n result = await createWorkbenchViteServer({\n cacheDir,\n cliConfig,\n httpHost,\n mode,\n output,\n reactStrictMode,\n workbenchPort,\n workDir,\n })\n } catch (err) {\n workbenchLock.release()\n throw err\n }\n\n if (!result) {\n workbenchLock.release()\n return {close: noop, httpHost, workbenchAvailable: false, workbenchPort}\n }\n\n const {actualPort, close} = result\n workbenchLock.updatePort(actualPort)\n\n return {\n close: async () => {\n workbenchLock.release()\n await close()\n },\n httpHost,\n workbenchAvailable: true,\n workbenchPort: actualPort,\n }\n}\n\ninterface CreateWorkbenchViteServerOptions {\n cacheDir: string\n cliConfig: CliConfig\n httpHost: string | undefined\n mode: 'development' | 'preview'\n output: Output\n reactStrictMode: boolean\n workbenchPort: number\n workDir: string\n}\n\ninterface CreateWorkbenchViteServerResult {\n actualPort: number\n close: () => Promise<void>\n}\n\nasync function createWorkbenchViteServer(\n options: CreateWorkbenchViteServerOptions,\n): Promise<CreateWorkbenchViteServerResult | undefined> {\n const {cacheDir, cliConfig, httpHost, mode, output, reactStrictMode, workbenchPort, workDir} =\n options\n\n // `preview` loads `.env.development` (the env hook treats only `build`/`deploy`\n // as production), which points the workbench UI at a local dev server that\n // isn't running here. Ignore the override and load the deployed UI instead.\n const remoteUrl =\n mode === 'preview'\n ? undefined\n : parseRemoteUrl(process.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL)\n\n const organizationId = resolveOrganizationId(cliConfig)\n\n devDebug('Writing workbench runtime files')\n const root = await writeWorkbenchRuntime({\n cwd: workDir,\n organizationId,\n reactStrictMode,\n remoteUrl,\n })\n\n const viteConfig: InlineConfig = {\n // Custom cache directory so sanity's vite cache doesn't conflict with local vite projects\n cacheDir,\n configFile: false,\n define: {\n __SANITY_STAGING__: isStaging(),\n 'import.meta.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL': JSON.stringify(remoteUrl),\n },\n logLevel: 'warn',\n mode: 'development',\n optimizeDeps: {\n // Keep this entry out of pre-bundling so Vite injects its HMR context.\n exclude: [renderDashboardEntry],\n },\n // viteReact looks inert here — it transforms none of the host's own modules —\n // but it's load-bearing for the remotes. It serves the Fast Refresh runtime at\n // /@react-refresh and injects the preamble that defines window.$RefreshReg$. The\n // federated remotes loaded into this page are react-refresh transformed, so\n // without the preamble they throw \"can't detect preamble\", and without the\n // runtime their /@react-refresh import (wired by @module-federation/vite's\n // remoteHmr) fails. Dropping it as dead code broke every panel; see #1262.\n plugins: [viteReact(), ...(remoteUrl ? [remoteManifestPreloadHeaderPlugin(remoteUrl)] : [])],\n resolve: {\n // The generated Vite root cannot reliably resolve this package.\n alias: {[renderDashboardEntry]: renderDashboardPath},\n dedupe: ['react', 'react-dom'],\n },\n root,\n server: {\n host: httpHost,\n port: workbenchPort,\n strictPort: false,\n warmup: {\n clientFiles: ['./workbench.js'],\n },\n },\n }\n\n devDebug('Creating workbench vite server')\n const server = await createServer(viteConfig)\n try {\n await server.listen()\n } catch (err) {\n await server.close()\n output.warn(\n `Workbench dev server failed to start: ${err instanceof Error ? err.message : String(err)}`,\n )\n return undefined\n }\n\n // Vite may have picked a different port if the desired one was occupied\n const addr = server.httpServer?.address()\n const actualPort = typeof addr === 'object' && addr ? addr.port : workbenchPort\n\n // Fire-and-forget: warm the workbench remote's Vite transform pipeline so\n // the first browser request hits a pre-populated module graph.\n if (remoteUrl) {\n fetch(remoteUrl)\n .then((r) => r.body?.cancel())\n .catch(() => {})\n devDebug('Warming workbench remote at %s', remoteUrl)\n }\n\n const detachBridge = attachViteDevServerBridge(server)\n\n return {\n actualPort,\n close: async () => {\n detachBridge()\n await server.close()\n },\n }\n}\n\n// Workbench is opted into via `defineApplication`, which carries the\n// organization ID. Deliberately no fallback (e.g. resolving it from the\n// configured project): the lookup would need an authenticated user and an\n// API round-trip on every startup for something the opt-in already declares.\nconst resolveOrganizationId = (cliConfig: CliConfig): string => {\n if (cliConfig.app?.organizationId) {\n return cliConfig.app.organizationId\n }\n\n throw new Error(\n 'Workbench requires an organization ID. Pass \"organizationId\" to defineApplication() in sanity.cli.ts.',\n )\n}\n\n// Restricts protocol to http(s) so the URL is safe to interpolate into HTML\n// attributes and Link headers downstream.\nconst remoteUrlSchema = z.url({normalize: true, protocol: /^https?$/})\n\nfunction parseRemoteUrl(value: string | undefined): string | undefined {\n if (!value) return undefined\n\n const result = remoteUrlSchema.safeParse(value)\n\n if (!result.success) {\n throw new Error(\n `Invalid SANITY_INTERNAL_WORKBENCH_REMOTE_URL: ${value} (must be an http(s) URL)`,\n )\n }\n\n return result.data\n}\n\n/**\n * Sets a `Link: <remoteUrl>; rel=preload; as=fetch; crossorigin` response header\n * on the index document so the browser can start fetching the Module Federation\n * manifest as soon as response headers arrive — before HTML parsing reaches the\n * in-head preconnect hint. `as=fetch` matches how the federation runtime later\n * retrieves the JSON manifest, allowing the preload entry to satisfy that fetch.\n */\nfunction remoteManifestPreloadHeaderPlugin(remoteUrl: string): Plugin {\n return {\n apply: 'serve',\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const pathname = (req.url || '/').split('?')[0]\n if (pathname === '/' || pathname === '/index.html') {\n res.setHeader('Link', `<${remoteUrl}>; rel=preload; as=fetch; crossorigin`)\n }\n next()\n })\n },\n name: 'sanity:workbench-remote-preload-header',\n }\n}\n"],"names":["fileURLToPath","subdebug","isStaging","viteReact","createServer","z","isWorkbenchApp","isWorkbenchConfig","createExposesTracker","acquireWorkbenchLock","getRegisteredServers","isConfigOnlyServer","readWorkbenchLock","watchRegistry","toWireInterface","writeWorkbenchRuntime","devDebug","renderDashboardEntry","renderDashboardPath","URL","url","noop","isLocalApp","server","toApplicationsPayload","servers","applications","filter","map","host","id","interfaces","manifest","name","port","projectId","reference","type","iface","configs","flatMap","appType","moduleName","version","config","remoteURL","attachViteDevServerBridge","ws","on","_","client","send","setTracker","registryWatcher","hasChanged","close","startWorkbenchRemoteCoordinator","options","httpHost","lock","existing","pid","detachBridge","release","startWorkbenchDevServer","cacheDir","cliConfig","httpPort","workbenchPort","mode","output","reactStrictMode","workDir","app","workbenchAvailable","workbenchLock","result","createWorkbenchViteServer","err","actualPort","updatePort","remoteUrl","undefined","parseRemoteUrl","process","env","SANITY_INTERNAL_WORKBENCH_REMOTE_URL","organizationId","resolveOrganizationId","root","cwd","viteConfig","configFile","define","__SANITY_STAGING__","JSON","stringify","logLevel","optimizeDeps","exclude","plugins","remoteManifestPreloadHeaderPlugin","resolve","alias","dedupe","strictPort","warmup","clientFiles","listen","warn","Error","message","String","addr","httpServer","address","fetch","then","r","body","cancel","catch","remoteUrlSchema","normalize","protocol","value","safeParse","success","data","apply","configureServer","middlewares","use","req","res","next","pathname","split","setHeader"],"mappings":"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"}
@@ -8,7 +8,7 @@
8
8
  const { surface, ...rest } = iface;
9
9
  return {
10
10
  ...rest,
11
- type: surface
11
+ type: surface === 'window' ? 'app' : surface
12
12
  };
13
13
  }
14
14
  return iface;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/dev/toWireInterface.ts"],"sourcesContent":["import {type DevServerInterface} from './deriveConfigs.js'\n\n// The registry stores view interfaces discriminated on `surface` (the author\n// API's word), but the workbench remote — like the deployed application record\n// (see viewDeployment.ts) — keys every interface on `type`. This module is the\n// single, strictly-typed boundary that converts the internal `surface` shape to\n// the wire `type` shape for local dev, so the two can never drift again: the\n// return type carries no `surface`, so a raw registry interface cannot be sent\n// to the remote without passing through here.\n\n/** A registry view interface — the members discriminated on `surface`. */\ntype ViewInterface = Extract<DevServerInterface, {surface: unknown}>\n/** A registry worker interface — already keyed on `type`. */\ntype WorkerInterface = Extract<DevServerInterface, {type: unknown}>\n\n/**\n * An interface as the workbench remote consumes it: every member keyed on\n * `type`. Views have their `surface` renamed to `type`; workers pass through.\n * @internal\n */\nexport type WorkbenchWireInterface =\n | (Omit<ViewInterface, 'surface'> & {type: ViewInterface['surface']})\n | WorkerInterface\n\n/**\n * Convert a registry interface to the remote's wire shape. Views rename\n * `surface` → `type`; workers (already `type`) pass through untouched. The only\n * surface→type conversion for local dev — mirrors the deploy boundary.\n * @internal\n */\nexport function toWireInterface(iface: DevServerInterface): WorkbenchWireInterface {\n if ('surface' in iface) {\n const {surface, ...rest} = iface\n return {...rest, type: surface}\n }\n return iface\n}\n"],"names":["toWireInterface","iface","surface","rest","type"],"mappings":"AAwBA;;;;;CAKC,GACD,OAAO,SAASA,gBAAgBC,KAAyB;IACvD,IAAI,aAAaA,OAAO;QACtB,MAAM,EAACC,OAAO,EAAE,GAAGC,MAAK,GAAGF;QAC3B,OAAO;YAAC,GAAGE,IAAI;YAAEC,MAAMF;QAAO;IAChC;IACA,OAAOD;AACT"}
1
+ {"version":3,"sources":["../../../src/actions/dev/toWireInterface.ts"],"sourcesContent":["import {type DevServerInterface} from './deriveConfigs.js'\n\n// The registry stores view interfaces discriminated on `surface` (the author\n// API's word), but the workbench remote — like the deployed application record\n// (see viewDeployment.ts) — keys every interface on `type`. This module is the\n// single, strictly-typed boundary that converts the internal `surface` shape to\n// the wire `type` shape for local dev, so the two can never drift again: the\n// return type carries no `surface`, so a raw registry interface cannot be sent\n// to the remote without passing through here.\n\n/** A registry view interface — the members discriminated on `surface`. */\ntype ViewInterface = Extract<DevServerInterface, {surface: unknown}>\n/** A registry worker interface — already keyed on `type`. */\ntype WorkerInterface = Extract<DevServerInterface, {type: unknown}>\n\n/**\n * An interface as the workbench remote consumes it: every member keyed on\n * `type`. Views have their `surface` renamed to `type`; workers pass through.\n * @internal\n */\nexport type WorkbenchWireInterface =\n | (Omit<ViewInterface, 'surface'> & {\n type: 'app' | Exclude<ViewInterface['surface'], 'window'>\n })\n | WorkerInterface\n\n/**\n * Convert a registry interface to the remote's wire shape. Views rename\n * `surface` → `type`; workers (already `type`) pass through untouched. The only\n * surface→type conversion for local dev — mirrors the deploy boundary.\n * @internal\n */\nexport function toWireInterface(iface: DevServerInterface): WorkbenchWireInterface {\n if ('surface' in iface) {\n const {surface, ...rest} = iface\n return {...rest, type: surface === 'window' ? 'app' : surface}\n }\n return iface\n}\n"],"names":["toWireInterface","iface","surface","rest","type"],"mappings":"AA0BA;;;;;CAKC,GACD,OAAO,SAASA,gBAAgBC,KAAyB;IACvD,IAAI,aAAaA,OAAO;QACtB,MAAM,EAACC,OAAO,EAAE,GAAGC,MAAK,GAAGF;QAC3B,OAAO;YAAC,GAAGE,IAAI;YAAEC,MAAMF,YAAY,WAAW,QAAQA;QAAO;IAC/D;IACA,OAAOD;AACT"}
@@ -1,14 +1,14 @@
1
- // `sanity.cli.ts` templates for workbench (`unstable_defineApp`) projects,
2
- // consumed by the CLI's `init` scaffolding. The branded `unstable_defineApp`
1
+ // `sanity.cli.ts` templates for workbench (`defineApplication`) projects,
2
+ // consumed by the CLI's `init` scaffolding. The branded `defineApplication`
3
3
  // result is the sole workbench (module-federation) opt-in, so its config shape
4
4
  // is workbench's to own; the CLI keeps the non-workbench templates and the
5
5
  // `%placeholder%` substitution. `%slug%`/`%title%`/etc. are filled in by the
6
6
  // CLI's template processor.
7
7
  /** App scaffold — `entry` auto-declares the navigable app view. */ export const workbenchAppConfigTemplate = `
8
- import {defineCliConfig, unstable_defineApp} from 'sanity/cli'
8
+ import {defineApplication, defineCliConfig} from 'sanity/cli'
9
9
 
10
10
  export default defineCliConfig({
11
- app: unstable_defineApp({
11
+ app: defineApplication({
12
12
  title: '%title%',
13
13
  slug: '%slug%',
14
14
  organizationId: '%organizationId%',
@@ -20,14 +20,14 @@ export default defineCliConfig({
20
20
  * Studio scaffold — brands with slug/title only, no `entry` (studio app views
21
21
  * aren't implemented yet).
22
22
  */ export const workbenchStudioConfigTemplate = `
23
- import {defineCliConfig, unstable_defineApp} from 'sanity/cli'
23
+ import {defineApplication, defineCliConfig} from 'sanity/cli'
24
24
 
25
25
  export default defineCliConfig({
26
26
  api: {
27
27
  projectId: '%projectId%',
28
28
  dataset: '%dataset%'
29
29
  },
30
- app: unstable_defineApp({
30
+ app: defineApplication({
31
31
  title: '%title%',
32
32
  slug: '%slug%',
33
33
  organizationId: '%organizationId%',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/init/cliConfig.ts"],"sourcesContent":["// `sanity.cli.ts` templates for workbench (`unstable_defineApp`) projects,\n// consumed by the CLI's `init` scaffolding. The branded `unstable_defineApp`\n// result is the sole workbench (module-federation) opt-in, so its config shape\n// is workbench's to own; the CLI keeps the non-workbench templates and the\n// `%placeholder%` substitution. `%slug%`/`%title%`/etc. are filled in by the\n// CLI's template processor.\n\n/** App scaffold — `entry` auto-declares the navigable app view. */\nexport const workbenchAppConfigTemplate = `\nimport {defineCliConfig, unstable_defineApp} from 'sanity/cli'\n\nexport default defineCliConfig({\n app: unstable_defineApp({\n title: '%title%',\n slug: '%slug%',\n organizationId: '%organizationId%',\n entry: '%entry%',\n }),\n})\n`\n\n/**\n * Studio scaffold — brands with slug/title only, no `entry` (studio app views\n * aren't implemented yet).\n */\nexport const workbenchStudioConfigTemplate = `\nimport {defineCliConfig, unstable_defineApp} from 'sanity/cli'\n\nexport default defineCliConfig({\n api: {\n projectId: '%projectId%',\n dataset: '%dataset%'\n },\n app: unstable_defineApp({\n title: '%title%',\n slug: '%slug%',\n organizationId: '%organizationId%',\n }),\n deployment: {\n /**\n * Enable auto-updates for studios.\n * Learn more at https://www.sanity.io/docs/studio/latest-version-of-sanity#k47faf43faf56\n */\n autoUpdates: __BOOL__autoUpdates__,\n },\n})\n`\n"],"names":["workbenchAppConfigTemplate","workbenchStudioConfigTemplate"],"mappings":"AAAA,2EAA2E;AAC3E,6EAA6E;AAC7E,+EAA+E;AAC/E,2EAA2E;AAC3E,6EAA6E;AAC7E,4BAA4B;AAE5B,iEAAiE,GACjE,OAAO,MAAMA,6BAA6B,CAAC;;;;;;;;;;;AAW3C,CAAC,CAAA;AAED;;;CAGC,GACD,OAAO,MAAMC,gCAAgC,CAAC;;;;;;;;;;;;;;;;;;;;;AAqB9C,CAAC,CAAA"}
1
+ {"version":3,"sources":["../../../src/actions/init/cliConfig.ts"],"sourcesContent":["// `sanity.cli.ts` templates for workbench (`defineApplication`) projects,\n// consumed by the CLI's `init` scaffolding. The branded `defineApplication`\n// result is the sole workbench (module-federation) opt-in, so its config shape\n// is workbench's to own; the CLI keeps the non-workbench templates and the\n// `%placeholder%` substitution. `%slug%`/`%title%`/etc. are filled in by the\n// CLI's template processor.\n\n/** App scaffold — `entry` auto-declares the navigable app view. */\nexport const workbenchAppConfigTemplate = `\nimport {defineApplication, defineCliConfig} from 'sanity/cli'\n\nexport default defineCliConfig({\n app: defineApplication({\n title: '%title%',\n slug: '%slug%',\n organizationId: '%organizationId%',\n entry: '%entry%',\n }),\n})\n`\n\n/**\n * Studio scaffold — brands with slug/title only, no `entry` (studio app views\n * aren't implemented yet).\n */\nexport const workbenchStudioConfigTemplate = `\nimport {defineApplication, defineCliConfig} from 'sanity/cli'\n\nexport default defineCliConfig({\n api: {\n projectId: '%projectId%',\n dataset: '%dataset%'\n },\n app: defineApplication({\n title: '%title%',\n slug: '%slug%',\n organizationId: '%organizationId%',\n }),\n deployment: {\n /**\n * Enable auto-updates for studios.\n * Learn more at https://www.sanity.io/docs/studio/latest-version-of-sanity#k47faf43faf56\n */\n autoUpdates: __BOOL__autoUpdates__,\n },\n})\n`\n"],"names":["workbenchAppConfigTemplate","workbenchStudioConfigTemplate"],"mappings":"AAAA,0EAA0E;AAC1E,4EAA4E;AAC5E,+EAA+E;AAC/E,2EAA2E;AAC3E,6EAA6E;AAC7E,4BAA4B;AAE5B,iEAAiE,GACjE,OAAO,MAAMA,6BAA6B,CAAC;;;;;;;;;;;AAW3C,CAAC,CAAA;AAED;;;CAGC,GACD,OAAO,MAAMC,gCAAgC,CAAC;;;;;;;;;;;;;;;;;;;;;AAqB9C,CAAC,CAAA"}
package/dist/contract.js CHANGED
@@ -30,9 +30,9 @@ import { z } from 'zod/mini';
30
30
  'banner'
31
31
  ]);
32
32
  const DockGroupSchema = z.enum([
33
- 'dock.system',
34
- 'dock.applications',
35
- 'dock.user'
33
+ 'system',
34
+ 'applications',
35
+ 'user'
36
36
  ]);
37
37
  /** @internal */ export const DockSchema = z.object({
38
38
  group: z.optional(DockGroupSchema),
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/contract.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\n// Shared module-federation extension contract: interface (view/service) and\n// config declaration schemas, plus the versions the build stamps.\n// `zod/mini` keeps the bundle small.\n\n/** @internal */\nexport const VIEW_CONTRACT_VERSION = 1\n\n/** @internal */\nexport const SERVICE_CONTRACT_VERSION = 1\n\n/** @internal */\nexport const MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION = 1\n\n/**\n * A view component. The return is opaque so the runtime helpers carry no React\n * dependency — the generated artifact renders it with the app's own React.\n * @public\n */\nexport type ViewComponent<TProps> = (props: TProps) => unknown\n\n/** @public */\nexport interface ViewComponentBaseProps<TView> {\n view: TView\n}\n\n/** Component slots per view surface; windows load outside the component artifact path. @internal */\nexport const VIEW_COMPONENTS = {\n asset_source: ['asset_source'],\n panel: ['title', 'panel'],\n tile: ['tile'],\n window: [],\n} as const satisfies Record<string, readonly string[]>\n\n/** @public */\nexport type ViewSurface = keyof typeof VIEW_COMPONENTS\n\n/**\n * A tile's footprint family — the shape it occupies on the dashboard. Modelled\n * on iOS WidgetKit families, not a linear scale: `banner` is full-width and\n * shallow, which a `small`→`large` magnitude can't express. The host maps a\n * family to a layout slot; the component reads it to render per footprint.\n * @public\n */\nexport const TileSizeSchema = z.enum(['small', 'large', 'banner'])\n\n/** @public */\nexport type TileSize = z.infer<typeof TileSizeSchema>\n\n/** @public */\nexport type ServiceType = 'worker'\n\nconst DockGroupSchema = z.enum(['dock.system', 'dock.applications', 'dock.user'])\n\n/** @public */\nexport type DockGroup = z.output<typeof DockGroupSchema>\n\n/** @internal */\nexport const DockSchema = z.object({\n group: z.optional(DockGroupSchema),\n order: z.optional(z.number()),\n})\n\n/** @internal */\nexport type Dock = z.infer<typeof DockSchema>\n\n/** @internal */\nexport const ViewPlacementMetadataSchema = z.object({dock: DockSchema})\n\n/** @internal */\nexport type ViewPlacementMetadata = z.infer<typeof ViewPlacementMetadataSchema>\n\n/**\n * A tile's interface metadata: its footprint `size` and an optional `order`\n * the dashboard sorts on, ascending. Both are authored as top-level view fields\n * (see {@link InterfaceDeclarationSchema}) but stored on the record as metadata.\n * @internal\n */\nexport const TileInterfaceMetadataSchema = z.object({\n order: z.optional(z.number()),\n size: TileSizeSchema,\n})\n\n/** @internal */\nexport type TileInterfaceMetadata = z.infer<typeof TileInterfaceMetadataSchema>\n\n/**\n * The contract version each interface type advertises, so the host can check it\n * renders/runs what it expects.\n * @internal\n */\nconst INTERFACE_CONTRACT_VERSIONS = {\n asset_source: VIEW_CONTRACT_VERSION,\n panel: VIEW_CONTRACT_VERSION,\n tile: VIEW_CONTRACT_VERSION,\n window: undefined,\n worker: SERVICE_CONTRACT_VERSION,\n} as const\n\n/** Every interface type an app exposes — a window, a view, or a service. */\nexport type InterfaceKind = keyof typeof INTERFACE_CONTRACT_VERSIONS\n\n/** @internal */\nexport function interfaceContractVersion(kind: InterfaceKind): string | undefined {\n const version = INTERFACE_CONTRACT_VERSIONS[kind]\n return version === undefined ? undefined : String(version)\n}\n\n/**\n * The module-federation id a build exposes an interface at. Dev stamps the same\n * id a deploy would, so the workbench loads a local interface like a deployed one.\n * @internal\n */\nexport function interfaceModuleId(kind: string, name: string): string {\n switch (kind) {\n case 'asset_source':\n case 'panel':\n case 'tile': {\n return `views/${name}`\n }\n case 'window': {\n return 'App'\n }\n case 'worker': {\n return `services/${name}`\n }\n default: {\n throw new Error(`Cannot derive a moduleId for unknown interface kind: ${kind}`)\n }\n }\n}\n\n// Shared `name` + `src`; `kind` only tailors the validation message.\nfunction extensionDeclarationFields(kind: 'Field' | 'View' | 'Web worker') {\n const pattern = /^[a-zA-Z0-9_-]+$/\n return {\n name: z.string().check(z.regex(pattern, `${kind} \\`name\\` must match ${pattern}`)),\n src: z.string(),\n }\n}\n\n// Every interface shares `name` + `src` + a display `title`,\n// which Brett requires on the record each becomes.\nfunction interfaceDeclarationFields(kind: 'View' | 'Web worker') {\n return {\n ...extensionDeclarationFields(kind),\n title: z.string(`${kind} \\`title\\` is required`),\n }\n}\n\nconst PanelViewSchema = z.object({\n surface: z.literal('panel'),\n ...interfaceDeclarationFields('View'),\n dock: z.optional(DockSchema),\n})\n\n/** @public */\nexport type PanelView = z.output<typeof PanelViewSchema>\n\n/** @public */\nexport type DefinePanelViewInput = Omit<PanelView, 'surface'>\n\n/** @public */\nexport function definePanelView(view: DefinePanelViewInput): PanelView {\n return {...view, surface: 'panel'}\n}\n\nconst WindowViewSchema = z.object({\n surface: z.literal('window'),\n ...interfaceDeclarationFields('View'),\n dock: z.optional(DockSchema),\n})\n\n/** @public */\nexport type WindowView = z.output<typeof WindowViewSchema>\n\n/** @public */\nexport type DefineWindowViewInput = Omit<WindowView, 'surface'>\n\n/** @public */\nexport function defineWindowView(view: DefineWindowViewInput): WindowView {\n return {...view, surface: 'window'}\n}\n\nconst AssetSourceViewSchema = z.object({\n surface: z.literal('asset_source'),\n ...interfaceDeclarationFields('View'),\n})\n\n/** @public */\nexport type AssetSourceView = z.output<typeof AssetSourceViewSchema>\n\n/** @public */\nexport type DefineAssetSourceViewInput = Omit<AssetSourceView, 'surface'>\n\n/** @public */\nexport function defineAssetSourceView(view: DefineAssetSourceViewInput): AssetSourceView {\n return {...view, surface: 'asset_source'}\n}\n\nconst TileViewSchema = z.object({\n surface: z.literal('tile'),\n ...interfaceDeclarationFields('View'),\n /** Sort position within its layout track, ascending. Optional. */\n order: z.optional(z.number()),\n /** Footprint family the dashboard lays the tile out by. */\n size: TileSizeSchema,\n})\n\n/** @public */\nexport type TileView = z.output<typeof TileViewSchema>\n\n/** @public */\nexport type DefineTileViewInput = Omit<TileView, 'surface'>\n\n/** @public */\nexport function defineTileView(view: DefineTileViewInput): TileView {\n return {...view, surface: 'tile'}\n}\n\n/** @internal */\nexport const InterfaceDeclarationSchema = z.discriminatedUnion('surface', [\n WindowViewSchema,\n PanelViewSchema,\n AssetSourceViewSchema,\n TileViewSchema,\n])\n\n/** @public */\nexport type ViewDeclaration = z.output<typeof InterfaceDeclarationSchema>\n\nconst WebWorkerSchema = z.object({\n type: z.literal('worker'),\n ...interfaceDeclarationFields('Web worker'),\n})\n\n/** @public */\nexport type WebWorker = z.output<typeof WebWorkerSchema>\n\n/** @public */\nexport type DefineWebWorkerInput = Omit<WebWorker, 'type'>\n\n/** @public */\nexport function defineWebWorker(webWorker: DefineWebWorkerInput): WebWorker {\n return {...webWorker, type: 'worker'}\n}\n\n/** @internal */\nexport const ServiceDeclarationSchema = z.discriminatedUnion('type', [WebWorkerSchema])\n\nconst MediaLibraryFieldSchema = z.object({\n ...extensionDeclarationFields('Field'),\n public: z.optional(z.boolean()),\n title: z.string(),\n})\n\n/**\n * Stamped where the config crosses a boundary so the authoring model doesn't carry a constant discriminator.\n * @internal\n */\nexport const INSTALLATION_CONFIG_TYPE = 'installation_config'\n\n// `appType` is stamped by `unstable_defineMediaLibrary`, never authored.\nconst MediaLibraryConfigSchema = z.object({\n appType: z.literal('media-library'),\n fields: z\n .array(MediaLibraryFieldSchema)\n .check(\n z.refine(\n (fields) => new Set(fields.map((field) => field.name)).size === fields.length,\n 'Field `name` must be unique within a media library',\n ),\n ),\n})\n\n/**\n * A workbench config's built value, keyed by `appType`; deploys as a versioned\n * snapshot, not an interface.\n * @internal\n */\nexport const ConfigSchema = z.discriminatedUnion('appType', [MediaLibraryConfigSchema])\n\n/**\n * The `{appType, fields}` config value the build expands into a federation\n * remote and the deploy summarizes.\n * @internal\n */\nexport type WorkbenchConfigValue = z.output<typeof ConfigSchema>\n"],"names":["z","VIEW_CONTRACT_VERSION","SERVICE_CONTRACT_VERSION","MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION","VIEW_COMPONENTS","asset_source","panel","tile","window","TileSizeSchema","enum","DockGroupSchema","DockSchema","object","group","optional","order","number","ViewPlacementMetadataSchema","dock","TileInterfaceMetadataSchema","size","INTERFACE_CONTRACT_VERSIONS","undefined","worker","interfaceContractVersion","kind","version","String","interfaceModuleId","name","Error","extensionDeclarationFields","pattern","string","check","regex","src","interfaceDeclarationFields","title","PanelViewSchema","surface","literal","definePanelView","view","WindowViewSchema","defineWindowView","AssetSourceViewSchema","defineAssetSourceView","TileViewSchema","defineTileView","InterfaceDeclarationSchema","discriminatedUnion","WebWorkerSchema","type","defineWebWorker","webWorker","ServiceDeclarationSchema","MediaLibraryFieldSchema","public","boolean","INSTALLATION_CONFIG_TYPE","MediaLibraryConfigSchema","appType","fields","array","refine","Set","map","field","length","ConfigSchema"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/contract.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\n// Shared module-federation extension contract: interface (view/service) and\n// config declaration schemas, plus the versions the build stamps.\n// `zod/mini` keeps the bundle small.\n\n/** @internal */\nexport const VIEW_CONTRACT_VERSION = 1\n\n/** @internal */\nexport const SERVICE_CONTRACT_VERSION = 1\n\n/** @internal */\nexport const MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION = 1\n\n/**\n * A view component. The return is opaque so the runtime helpers carry no React\n * dependency — the generated artifact renders it with the app's own React.\n * @public\n */\nexport type ViewComponent<TProps> = (props: TProps) => unknown\n\n/** @public */\nexport interface ViewComponentBaseProps<TView> {\n view: TView\n}\n\n/** Component slots per view surface; windows load outside the component artifact path. @internal */\nexport const VIEW_COMPONENTS = {\n asset_source: ['asset_source'],\n panel: ['title', 'panel'],\n tile: ['tile'],\n window: [],\n} as const satisfies Record<string, readonly string[]>\n\n/** @public */\nexport type ViewSurface = keyof typeof VIEW_COMPONENTS\n\n/**\n * A tile's footprint family — the shape it occupies on the dashboard. Modelled\n * on iOS WidgetKit families, not a linear scale: `banner` is full-width and\n * shallow, which a `small`→`large` magnitude can't express. The host maps a\n * family to a layout slot; the component reads it to render per footprint.\n * @public\n */\nexport const TileSizeSchema = z.enum(['small', 'large', 'banner'])\n\n/** @public */\nexport type TileSize = z.infer<typeof TileSizeSchema>\n\n/** @public */\nexport type ServiceType = 'worker'\n\nconst DockGroupSchema = z.enum(['system', 'applications', 'user'])\n\n/** @public */\nexport type DockGroup = z.output<typeof DockGroupSchema>\n\n/** @internal */\nexport const DockSchema = z.object({\n group: z.optional(DockGroupSchema),\n order: z.optional(z.number()),\n})\n\n/** @internal */\nexport type Dock = z.infer<typeof DockSchema>\n\n/** @internal */\nexport const ViewPlacementMetadataSchema = z.object({dock: DockSchema})\n\n/** @internal */\nexport type ViewPlacementMetadata = z.infer<typeof ViewPlacementMetadataSchema>\n\n/**\n * A tile's interface metadata: its footprint `size` and an optional `order`\n * the dashboard sorts on, ascending. Both are authored as top-level view fields\n * (see {@link InterfaceDeclarationSchema}) but stored on the record as metadata.\n * @internal\n */\nexport const TileInterfaceMetadataSchema = z.object({\n order: z.optional(z.number()),\n size: TileSizeSchema,\n})\n\n/** @internal */\nexport type TileInterfaceMetadata = z.infer<typeof TileInterfaceMetadataSchema>\n\n/**\n * The contract version each interface type advertises, so the host can check it\n * renders/runs what it expects.\n * @internal\n */\nconst INTERFACE_CONTRACT_VERSIONS = {\n asset_source: VIEW_CONTRACT_VERSION,\n panel: VIEW_CONTRACT_VERSION,\n tile: VIEW_CONTRACT_VERSION,\n window: undefined,\n worker: SERVICE_CONTRACT_VERSION,\n} as const\n\n/** Every interface type an app exposes — a window, a view, or a service. */\nexport type InterfaceKind = keyof typeof INTERFACE_CONTRACT_VERSIONS\n\n/** @internal */\nexport function interfaceContractVersion(kind: InterfaceKind): string | undefined {\n const version = INTERFACE_CONTRACT_VERSIONS[kind]\n return version === undefined ? undefined : String(version)\n}\n\n/**\n * The module-federation id a build exposes an interface at. Dev stamps the same\n * id a deploy would, so the workbench loads a local interface like a deployed one.\n * @internal\n */\nexport function interfaceModuleId(kind: string, name: string): string {\n switch (kind) {\n case 'asset_source':\n case 'panel':\n case 'tile': {\n return `views/${name}`\n }\n case 'window': {\n return 'App'\n }\n case 'worker': {\n return `services/${name}`\n }\n default: {\n throw new Error(`Cannot derive a moduleId for unknown interface kind: ${kind}`)\n }\n }\n}\n\n// Shared `name` + `src`; `kind` only tailors the validation message.\nfunction extensionDeclarationFields(kind: 'Field' | 'View' | 'Web worker') {\n const pattern = /^[a-zA-Z0-9_-]+$/\n return {\n name: z.string().check(z.regex(pattern, `${kind} \\`name\\` must match ${pattern}`)),\n src: z.string(),\n }\n}\n\n// Every interface shares `name` + `src` + a display `title`,\n// which Brett requires on the record each becomes.\nfunction interfaceDeclarationFields(kind: 'View' | 'Web worker') {\n return {\n ...extensionDeclarationFields(kind),\n title: z.string(`${kind} \\`title\\` is required`),\n }\n}\n\nconst PanelViewSchema = z.object({\n surface: z.literal('panel'),\n ...interfaceDeclarationFields('View'),\n dock: z.optional(DockSchema),\n})\n\n/** @public */\nexport type PanelView = z.output<typeof PanelViewSchema>\n\n/** @public */\nexport type DefinePanelViewInput = Omit<PanelView, 'surface'>\n\n/** @public */\nexport function definePanelView(view: DefinePanelViewInput): PanelView {\n return {...view, surface: 'panel'}\n}\n\nconst WindowViewSchema = z.object({\n surface: z.literal('window'),\n ...interfaceDeclarationFields('View'),\n dock: z.optional(DockSchema),\n})\n\n/** @public */\nexport type WindowView = z.output<typeof WindowViewSchema>\n\n/** @public */\nexport type DefineWindowViewInput = Omit<WindowView, 'surface'>\n\n/** @public */\nexport function defineWindowView(view: DefineWindowViewInput): WindowView {\n return {...view, surface: 'window'}\n}\n\nconst AssetSourceViewSchema = z.object({\n surface: z.literal('asset_source'),\n ...interfaceDeclarationFields('View'),\n})\n\n/** @public */\nexport type AssetSourceView = z.output<typeof AssetSourceViewSchema>\n\n/** @public */\nexport type DefineAssetSourceViewInput = Omit<AssetSourceView, 'surface'>\n\n/** @public */\nexport function defineAssetSourceView(view: DefineAssetSourceViewInput): AssetSourceView {\n return {...view, surface: 'asset_source'}\n}\n\nconst TileViewSchema = z.object({\n surface: z.literal('tile'),\n ...interfaceDeclarationFields('View'),\n /** Sort position within its layout track, ascending. Optional. */\n order: z.optional(z.number()),\n /** Footprint family the dashboard lays the tile out by. */\n size: TileSizeSchema,\n})\n\n/** @public */\nexport type TileView = z.output<typeof TileViewSchema>\n\n/** @public */\nexport type DefineTileViewInput = Omit<TileView, 'surface'>\n\n/** @public */\nexport function defineTileView(view: DefineTileViewInput): TileView {\n return {...view, surface: 'tile'}\n}\n\n/** @internal */\nexport const InterfaceDeclarationSchema = z.discriminatedUnion('surface', [\n WindowViewSchema,\n PanelViewSchema,\n AssetSourceViewSchema,\n TileViewSchema,\n])\n\n/** @public */\nexport type ViewDeclaration = z.output<typeof InterfaceDeclarationSchema>\n\nconst WebWorkerSchema = z.object({\n type: z.literal('worker'),\n ...interfaceDeclarationFields('Web worker'),\n})\n\n/** @public */\nexport type WebWorker = z.output<typeof WebWorkerSchema>\n\n/** @public */\nexport type DefineWebWorkerInput = Omit<WebWorker, 'type'>\n\n/** @public */\nexport function defineWebWorker(webWorker: DefineWebWorkerInput): WebWorker {\n return {...webWorker, type: 'worker'}\n}\n\n/** @internal */\nexport const ServiceDeclarationSchema = z.discriminatedUnion('type', [WebWorkerSchema])\n\nconst MediaLibraryFieldSchema = z.object({\n ...extensionDeclarationFields('Field'),\n public: z.optional(z.boolean()),\n title: z.string(),\n})\n\n/**\n * Stamped where the config crosses a boundary so the authoring model doesn't carry a constant discriminator.\n * @internal\n */\nexport const INSTALLATION_CONFIG_TYPE = 'installation_config'\n\n// `appType` is stamped by `unstable_defineMediaLibrary`, never authored.\nconst MediaLibraryConfigSchema = z.object({\n appType: z.literal('media-library'),\n fields: z\n .array(MediaLibraryFieldSchema)\n .check(\n z.refine(\n (fields) => new Set(fields.map((field) => field.name)).size === fields.length,\n 'Field `name` must be unique within a media library',\n ),\n ),\n})\n\n/**\n * A workbench config's built value, keyed by `appType`; deploys as a versioned\n * snapshot, not an interface.\n * @internal\n */\nexport const ConfigSchema = z.discriminatedUnion('appType', [MediaLibraryConfigSchema])\n\n/**\n * The `{appType, fields}` config value the build expands into a federation\n * remote and the deploy summarizes.\n * @internal\n */\nexport type WorkbenchConfigValue = z.output<typeof ConfigSchema>\n"],"names":["z","VIEW_CONTRACT_VERSION","SERVICE_CONTRACT_VERSION","MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION","VIEW_COMPONENTS","asset_source","panel","tile","window","TileSizeSchema","enum","DockGroupSchema","DockSchema","object","group","optional","order","number","ViewPlacementMetadataSchema","dock","TileInterfaceMetadataSchema","size","INTERFACE_CONTRACT_VERSIONS","undefined","worker","interfaceContractVersion","kind","version","String","interfaceModuleId","name","Error","extensionDeclarationFields","pattern","string","check","regex","src","interfaceDeclarationFields","title","PanelViewSchema","surface","literal","definePanelView","view","WindowViewSchema","defineWindowView","AssetSourceViewSchema","defineAssetSourceView","TileViewSchema","defineTileView","InterfaceDeclarationSchema","discriminatedUnion","WebWorkerSchema","type","defineWebWorker","webWorker","ServiceDeclarationSchema","MediaLibraryFieldSchema","public","boolean","INSTALLATION_CONFIG_TYPE","MediaLibraryConfigSchema","appType","fields","array","refine","Set","map","field","length","ConfigSchema"],"mappings":"AAAA,SAAQA,CAAC,QAAO,WAAU;AAE1B,4EAA4E;AAC5E,kEAAkE;AAClE,qCAAqC;AAErC,cAAc,GACd,OAAO,MAAMC,wBAAwB,EAAC;AAEtC,cAAc,GACd,OAAO,MAAMC,2BAA2B,EAAC;AAEzC,cAAc,GACd,OAAO,MAAMC,wCAAwC,EAAC;AActD,kGAAkG,GAClG,OAAO,MAAMC,kBAAkB;IAC7BC,cAAc;QAAC;KAAe;IAC9BC,OAAO;QAAC;QAAS;KAAQ;IACzBC,MAAM;QAAC;KAAO;IACdC,QAAQ,EAAE;AACZ,EAAsD;AAKtD;;;;;;CAMC,GACD,OAAO,MAAMC,iBAAiBT,EAAEU,IAAI,CAAC;IAAC;IAAS;IAAS;CAAS,EAAC;AAQlE,MAAMC,kBAAkBX,EAAEU,IAAI,CAAC;IAAC;IAAU;IAAgB;CAAO;AAKjE,cAAc,GACd,OAAO,MAAME,aAAaZ,EAAEa,MAAM,CAAC;IACjCC,OAAOd,EAAEe,QAAQ,CAACJ;IAClBK,OAAOhB,EAAEe,QAAQ,CAACf,EAAEiB,MAAM;AAC5B,GAAE;AAKF,cAAc,GACd,OAAO,MAAMC,8BAA8BlB,EAAEa,MAAM,CAAC;IAACM,MAAMP;AAAU,GAAE;AAKvE;;;;;CAKC,GACD,OAAO,MAAMQ,8BAA8BpB,EAAEa,MAAM,CAAC;IAClDG,OAAOhB,EAAEe,QAAQ,CAACf,EAAEiB,MAAM;IAC1BI,MAAMZ;AACR,GAAE;AAKF;;;;CAIC,GACD,MAAMa,8BAA8B;IAClCjB,cAAcJ;IACdK,OAAOL;IACPM,MAAMN;IACNO,QAAQe;IACRC,QAAQtB;AACV;AAKA,cAAc,GACd,OAAO,SAASuB,yBAAyBC,IAAmB;IAC1D,MAAMC,UAAUL,2BAA2B,CAACI,KAAK;IACjD,OAAOC,YAAYJ,YAAYA,YAAYK,OAAOD;AACpD;AAEA;;;;CAIC,GACD,OAAO,SAASE,kBAAkBH,IAAY,EAAEI,IAAY;IAC1D,OAAQJ;QACN,KAAK;QACL,KAAK;QACL,KAAK;YAAQ;gBACX,OAAO,CAAC,MAAM,EAAEI,MAAM;YACxB;QACA,KAAK;YAAU;gBACb,OAAO;YACT;QACA,KAAK;YAAU;gBACb,OAAO,CAAC,SAAS,EAAEA,MAAM;YAC3B;QACA;YAAS;gBACP,MAAM,IAAIC,MAAM,CAAC,qDAAqD,EAAEL,MAAM;YAChF;IACF;AACF;AAEA,qEAAqE;AACrE,SAASM,2BAA2BN,IAAqC;IACvE,MAAMO,UAAU;IAChB,OAAO;QACLH,MAAM9B,EAAEkC,MAAM,GAAGC,KAAK,CAACnC,EAAEoC,KAAK,CAACH,SAAS,GAAGP,KAAK,qBAAqB,EAAEO,SAAS;QAChFI,KAAKrC,EAAEkC,MAAM;IACf;AACF;AAEA,6DAA6D;AAC7D,mDAAmD;AACnD,SAASI,2BAA2BZ,IAA2B;IAC7D,OAAO;QACL,GAAGM,2BAA2BN,KAAK;QACnCa,OAAOvC,EAAEkC,MAAM,CAAC,GAAGR,KAAK,sBAAsB,CAAC;IACjD;AACF;AAEA,MAAMc,kBAAkBxC,EAAEa,MAAM,CAAC;IAC/B4B,SAASzC,EAAE0C,OAAO,CAAC;IACnB,GAAGJ,2BAA2B,OAAO;IACrCnB,MAAMnB,EAAEe,QAAQ,CAACH;AACnB;AAQA,YAAY,GACZ,OAAO,SAAS+B,gBAAgBC,IAA0B;IACxD,OAAO;QAAC,GAAGA,IAAI;QAAEH,SAAS;IAAO;AACnC;AAEA,MAAMI,mBAAmB7C,EAAEa,MAAM,CAAC;IAChC4B,SAASzC,EAAE0C,OAAO,CAAC;IACnB,GAAGJ,2BAA2B,OAAO;IACrCnB,MAAMnB,EAAEe,QAAQ,CAACH;AACnB;AAQA,YAAY,GACZ,OAAO,SAASkC,iBAAiBF,IAA2B;IAC1D,OAAO;QAAC,GAAGA,IAAI;QAAEH,SAAS;IAAQ;AACpC;AAEA,MAAMM,wBAAwB/C,EAAEa,MAAM,CAAC;IACrC4B,SAASzC,EAAE0C,OAAO,CAAC;IACnB,GAAGJ,2BAA2B,OAAO;AACvC;AAQA,YAAY,GACZ,OAAO,SAASU,sBAAsBJ,IAAgC;IACpE,OAAO;QAAC,GAAGA,IAAI;QAAEH,SAAS;IAAc;AAC1C;AAEA,MAAMQ,iBAAiBjD,EAAEa,MAAM,CAAC;IAC9B4B,SAASzC,EAAE0C,OAAO,CAAC;IACnB,GAAGJ,2BAA2B,OAAO;IACrC,gEAAgE,GAChEtB,OAAOhB,EAAEe,QAAQ,CAACf,EAAEiB,MAAM;IAC1B,yDAAyD,GACzDI,MAAMZ;AACR;AAQA,YAAY,GACZ,OAAO,SAASyC,eAAeN,IAAyB;IACtD,OAAO;QAAC,GAAGA,IAAI;QAAEH,SAAS;IAAM;AAClC;AAEA,cAAc,GACd,OAAO,MAAMU,6BAA6BnD,EAAEoD,kBAAkB,CAAC,WAAW;IACxEP;IACAL;IACAO;IACAE;CACD,EAAC;AAKF,MAAMI,kBAAkBrD,EAAEa,MAAM,CAAC;IAC/ByC,MAAMtD,EAAE0C,OAAO,CAAC;IAChB,GAAGJ,2BAA2B,aAAa;AAC7C;AAQA,YAAY,GACZ,OAAO,SAASiB,gBAAgBC,SAA+B;IAC7D,OAAO;QAAC,GAAGA,SAAS;QAAEF,MAAM;IAAQ;AACtC;AAEA,cAAc,GACd,OAAO,MAAMG,2BAA2BzD,EAAEoD,kBAAkB,CAAC,QAAQ;IAACC;CAAgB,EAAC;AAEvF,MAAMK,0BAA0B1D,EAAEa,MAAM,CAAC;IACvC,GAAGmB,2BAA2B,QAAQ;IACtC2B,QAAQ3D,EAAEe,QAAQ,CAACf,EAAE4D,OAAO;IAC5BrB,OAAOvC,EAAEkC,MAAM;AACjB;AAEA;;;CAGC,GACD,OAAO,MAAM2B,2BAA2B,sBAAqB;AAE7D,yEAAyE;AACzE,MAAMC,2BAA2B9D,EAAEa,MAAM,CAAC;IACxCkD,SAAS/D,EAAE0C,OAAO,CAAC;IACnBsB,QAAQhE,EACLiE,KAAK,CAACP,yBACNvB,KAAK,CACJnC,EAAEkE,MAAM,CACN,CAACF,SAAW,IAAIG,IAAIH,OAAOI,GAAG,CAAC,CAACC,QAAUA,MAAMvC,IAAI,GAAGT,IAAI,KAAK2C,OAAOM,MAAM,EAC7E;AAGR;AAEA;;;;CAIC,GACD,OAAO,MAAMC,eAAevE,EAAEoD,kBAAkB,CAAC,WAAW;IAACU;CAAyB,EAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/workbench-cli",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
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",
@@ -59,30 +59,29 @@
59
59
  "dependencies": {
60
60
  "@module-federation/runtime": "2.9.0",
61
61
  "@module-federation/vite": "1.21.0",
62
- "@sanity/types": "^6.11.0",
62
+ "@sanity/cli-core": "^3.6.1",
63
+ "@sanity/types": "^6.12.0",
63
64
  "@vitejs/plugin-react": "^6.1.1",
64
65
  "form-data": "^4.0.5",
65
66
  "rxjs": "^7.8.2",
66
- "tar-fs": "^3.1.2",
67
+ "tar": "^7.5.18",
67
68
  "vite": "^8.2.2",
68
- "zod": "^4.5.2",
69
- "@sanity/cli-core": "^3.6.0"
69
+ "zod": "^4.5.2"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@eslint/compat": "^2.1.0",
73
+ "@repo/package.config": "0.0.1",
74
+ "@repo/tsconfig": "3.70.0",
75
+ "@sanity/eslint-config-cli": "^1.1.3",
73
76
  "@sanity/pkg-utils": "^12.3.4",
74
77
  "@swc/cli": "^0.8.1",
75
78
  "@swc/core": "^1.15.43",
76
79
  "@types/node": "^22.20.0",
77
- "@types/tar-fs": "^2.0.4",
78
80
  "@vitest/coverage-istanbul": "^4.1.11",
79
81
  "eslint": "^10.7.0",
80
82
  "publint": "^0.3.21",
81
83
  "typescript": "^6.0.3",
82
- "vitest": "^4.1.11",
83
- "@repo/package.config": "0.0.1",
84
- "@repo/tsconfig": "3.70.0",
85
- "@sanity/eslint-config-cli": "^1.1.3"
84
+ "vitest": "^4.1.11"
86
85
  },
87
86
  "engines": {
88
87
  "node": ">=22.12"