@sanity/workbench-cli 1.2.0 → 1.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 (61) hide show
  1. package/dist/_exports/build.d.ts +22 -17
  2. package/dist/_exports/deploy.d.ts +169 -23
  3. package/dist/_exports/deploy.js +4 -1
  4. package/dist/_exports/deploy.js.map +1 -1
  5. package/dist/_exports/dev.d.ts +9 -5
  6. package/dist/_exports/index.d.ts +19 -15
  7. package/dist/_exports/undeploy.d.ts +248 -0
  8. package/dist/_exports/undeploy.js +3 -0
  9. package/dist/_exports/undeploy.js.map +1 -0
  10. package/dist/actions/build/artifact.js +2 -2
  11. package/dist/actions/build/artifact.js.map +1 -1
  12. package/dist/actions/build/configs/artifact.js +5 -5
  13. package/dist/actions/build/configs/artifact.js.map +1 -1
  14. package/dist/actions/build/vite/plugin.js +5 -0
  15. package/dist/actions/build/vite/plugin.js.map +1 -1
  16. package/dist/actions/build/vite/plugins/plugin-sanity-app-id.js +5 -3
  17. package/dist/actions/build/vite/plugins/plugin-sanity-app-id.js.map +1 -1
  18. package/dist/actions/build/vite/plugins/plugin-sanity-environment.js +26 -2
  19. package/dist/actions/build/vite/plugins/plugin-sanity-environment.js.map +1 -1
  20. package/dist/actions/deploy/buildExposes.js +59 -0
  21. package/dist/actions/deploy/buildExposes.js.map +1 -0
  22. package/dist/actions/deploy/checkBuiltOutput.js +4 -3
  23. package/dist/actions/deploy/checkBuiltOutput.js.map +1 -1
  24. package/dist/actions/deploy/deployConfig.js +63 -0
  25. package/dist/actions/deploy/deployConfig.js.map +1 -0
  26. package/dist/actions/deploy/deployWorkbenchApp.js +108 -0
  27. package/dist/actions/deploy/deployWorkbenchApp.js.map +1 -0
  28. package/dist/actions/deploy/getWorkbench.js +4 -4
  29. package/dist/actions/deploy/getWorkbench.js.map +1 -1
  30. package/dist/actions/dev/deriveInterfaces.js +43 -32
  31. package/dist/actions/dev/deriveInterfaces.js.map +1 -1
  32. package/dist/actions/dev/exposesSetId.js +8 -8
  33. package/dist/actions/dev/exposesSetId.js.map +1 -1
  34. package/dist/actions/dev/registry.js +22 -12
  35. package/dist/actions/dev/registry.js.map +1 -1
  36. package/dist/actions/dev/startDevManifestWatcher.js +2 -2
  37. package/dist/actions/dev/startDevManifestWatcher.js.map +1 -1
  38. package/dist/actions/dev/startDevServerRegistration.js +7 -7
  39. package/dist/actions/dev/startDevServerRegistration.js.map +1 -1
  40. package/dist/actions/dev/startWorkbenchDevServer.js +9 -6
  41. package/dist/actions/dev/startWorkbenchDevServer.js.map +1 -1
  42. package/dist/actions/dev/writeWorkbenchRuntime.js +4 -1
  43. package/dist/actions/dev/writeWorkbenchRuntime.js.map +1 -1
  44. package/dist/actions/undeploy/workbenchUndeployAdapter.js +150 -0
  45. package/dist/actions/undeploy/workbenchUndeployAdapter.js.map +1 -0
  46. package/dist/contract.js +16 -8
  47. package/dist/contract.js.map +1 -1
  48. package/dist/defineApp.js +25 -20
  49. package/dist/defineApp.js.map +1 -1
  50. package/dist/defineView.js.map +1 -1
  51. package/dist/resolveWorkbenchApp.js +4 -3
  52. package/dist/resolveWorkbenchApp.js.map +1 -1
  53. package/dist/services/apiVersion.js +5 -0
  54. package/dist/services/apiVersion.js.map +1 -0
  55. package/dist/services/applications.js +100 -0
  56. package/dist/services/applications.js.map +1 -0
  57. package/dist/services/installations.js +63 -0
  58. package/dist/services/installations.js.map +1 -0
  59. package/package.json +7 -3
  60. package/dist/actions/deploy/deployInstallationConfig.js +0 -91
  61. package/dist/actions/deploy/deployInstallationConfig.js.map +0 -1
@@ -0,0 +1,248 @@
1
+ import { UndeployAdapter } from "@sanity/cli-core/undeploy";
2
+ import { UndeployApplicationTarget } from "@sanity/cli-core/undeploy";
3
+ import { UndeployConfigTarget } from "@sanity/cli-core/undeploy";
4
+ import { z } from "zod/mini";
5
+
6
+ /**
7
+ * The undeploy adapter for workbench apps, mirroring what a workbench deploy
8
+ * creates: apps that expose interfaces delete their Brett application (the
9
+ * server soft-deletes its deployments and refuses singletons with active
10
+ * installations); a singleton without interfaces — the media library — deletes
11
+ * its installation's config snapshots instead.
12
+ */
13
+ export declare function createWorkbenchUndeployAdapter(options: {
14
+ appId: string | undefined;
15
+ organizationId: string | undefined;
16
+ type: "coreApp" | "studio";
17
+ workbench: DeployableWorkbenchApp;
18
+ }): UndeployAdapter<WorkbenchUndeployTarget>;
19
+
20
+ /**
21
+ * User-facing input for `unstable_defineApp`. Excludes the internal
22
+ * `applicationType`, `isSingleton`, and `config` — validated by the
23
+ * schema but not part of the public surface (Sanity-owned apps set them via
24
+ * `@ts-expect-error`).
25
+ * @public
26
+ */
27
+ declare type DefineAppInput = Omit<
28
+ z.output<typeof DefineAppInputSchema>,
29
+ "applicationType" | "config" | "isSingleton"
30
+ >;
31
+
32
+ /**
33
+ * Runtime-validation schema for `unstable_defineApp`. Validates the full shape
34
+ * including the internal `applicationType`; the user-facing `DefineAppInput`
35
+ * type below omits that field.
36
+ * @internal
37
+ */
38
+ declare const DefineAppInputSchema: z.ZodMiniObject<
39
+ {
40
+ applicationType: z.ZodMiniOptional<
41
+ z.ZodMiniEnum<{
42
+ "media-library": "media-library";
43
+ coreApp: "coreApp";
44
+ studio: "studio";
45
+ canvas: "canvas";
46
+ dashboard: "dashboard";
47
+ }>
48
+ >;
49
+ config: z.ZodMiniOptional<
50
+ z.ZodMiniDiscriminatedUnion<
51
+ [
52
+ z.ZodMiniObject<
53
+ {
54
+ appType: z.ZodMiniLiteral<"media-library">;
55
+ fields: z.ZodMiniArray<
56
+ z.ZodMiniObject<
57
+ {
58
+ public: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
59
+ title: z.ZodMiniString<string>;
60
+ name: z.ZodMiniString<string>;
61
+ src: z.ZodMiniString<string>;
62
+ },
63
+ z.core.$strip
64
+ >
65
+ >;
66
+ },
67
+ z.core.$strip
68
+ >,
69
+ ],
70
+ "appType"
71
+ >
72
+ >;
73
+ entry: z.ZodMiniOptional<z.ZodMiniString<string>>;
74
+ group: z.ZodMiniOptional<
75
+ z.ZodMiniEnum<{
76
+ "dock.system": "dock.system";
77
+ "dock.applications": "dock.applications";
78
+ "dock.user": "dock.user";
79
+ }>
80
+ >;
81
+ icon: z.ZodMiniOptional<z.ZodMiniString<string>>;
82
+ isSingleton: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
83
+ name: z.ZodMiniString<string>;
84
+ organizationId: z.ZodMiniString<string>;
85
+ priority: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
86
+ services: z.ZodMiniOptional<
87
+ z.ZodMiniArray<
88
+ z.ZodMiniDiscriminatedUnion<
89
+ [
90
+ z.ZodMiniObject<
91
+ {
92
+ title: z.ZodMiniOptional<z.ZodMiniString<string>>;
93
+ name: z.ZodMiniString<string>;
94
+ src: z.ZodMiniString<string>;
95
+ type: z.ZodMiniLiteral<"worker">;
96
+ },
97
+ z.core.$strip
98
+ >,
99
+ ],
100
+ "type"
101
+ >
102
+ >
103
+ >;
104
+ slug: z.ZodMiniOptional<z.ZodMiniString<string>>;
105
+ title: z.ZodMiniString<string>;
106
+ views: z.ZodMiniOptional<
107
+ z.ZodMiniArray<
108
+ z.ZodMiniDiscriminatedUnion<
109
+ [
110
+ z.ZodMiniObject<
111
+ {
112
+ title: z.ZodMiniOptional<z.ZodMiniString<string>>;
113
+ name: z.ZodMiniString<string>;
114
+ src: z.ZodMiniString<string>;
115
+ type: z.ZodMiniLiteral<"panel">;
116
+ },
117
+ z.core.$strip
118
+ >,
119
+ ],
120
+ "type"
121
+ >
122
+ >
123
+ >;
124
+ },
125
+ z.core.$strip
126
+ >;
127
+
128
+ /**
129
+ * The branded result of `unstable_defineApp`. Carries the same fields as the
130
+ * input plus the internal brand — users only ever see `DefineAppInput`.
131
+ * @public
132
+ */
133
+ declare interface DefineAppResult extends DefineAppInput {
134
+ readonly [WORKBENCH_APP]: true;
135
+ }
136
+
137
+ declare interface DeployableWorkbenchApp extends ResolvedWorkbenchApp {
138
+ /**
139
+ * Throws when the app exposes nothing (no entry, view, service, or config) —
140
+ * the remote would have nothing to load. Gated before any prompt or API call.
141
+ */
142
+ assertDeployable(): void;
143
+ /**
144
+ * Validates the app's declared views into the application-service payload.
145
+ * Throws when a view declaration is malformed.
146
+ */
147
+ buildViewDeploymentPayload(applicationId: string): ViewDeploymentPayload;
148
+ /**
149
+ * A singleton (the Media Library) that carries an config — deploy
150
+ * persists the config to the org's installation. Independent of the interfaces,
151
+ * which register regardless; non-singletons never carry a config.
152
+ */
153
+ deploySingletonConfig: boolean;
154
+ /** Declares something to host as an application — an entry, view, or service. */
155
+ hasInterfaces: boolean;
156
+ }
157
+
158
+ /** A view or service as the deploy report and `--json` output surface it. */
159
+ declare interface DeployedExpose {
160
+ name: string;
161
+ src: string;
162
+ title: string;
163
+ type: string;
164
+ }
165
+
166
+ /** @public */
167
+ declare interface ResolvedWorkbenchApp {
168
+ /** The app's unique `name` from `unstable_defineApp`. */
169
+ readonly name: string;
170
+ /** Background worker services the app declares. */
171
+ readonly services: NonNullable<DefineAppInput["services"]>;
172
+ /** Dock panel views the app declares. */
173
+ readonly views: NonNullable<DefineAppInput["views"]>;
174
+ /** Resolved app kind — `studio` or one of the SDK app types. */
175
+ readonly applicationType?: string;
176
+ /** Deploys on its own path, separate from the interfaces. */
177
+ readonly config?: WorkbenchApp["config"];
178
+ /** SDK app-view entrypoint, when declared. */
179
+ readonly entry?: string;
180
+ /** Explicit singleton flag (a Sanity-owned app); `undefined` when the app doesn't set it. */
181
+ readonly isSingleton?: boolean;
182
+ /** Hostname the application is created at on first deploy. */
183
+ readonly slug?: string;
184
+ }
185
+
186
+ declare type ViewDeploymentPayload = z.infer<
187
+ typeof viewDeploymentPayloadSchema
188
+ >;
189
+
190
+ /**
191
+ * Payload registering an app's views with the application service on deploy.
192
+ *
193
+ * Phase 1 stub: the service that stores views does not exist yet, so the
194
+ * payload is validated and logged only — never sent. Builds the contract the
195
+ * application-service endpoint will accept.
196
+ */
197
+ declare const viewDeploymentPayloadSchema: z.ZodMiniObject<
198
+ {
199
+ applicationId: z.ZodMiniString<string>;
200
+ views: z.ZodMiniArray<
201
+ z.ZodMiniObject<
202
+ {
203
+ name: z.ZodMiniString<string>;
204
+ src: z.ZodMiniString<string>;
205
+ type: z.ZodMiniEnum<{
206
+ panel: "panel";
207
+ }>;
208
+ },
209
+ z.core.$loose
210
+ >
211
+ >;
212
+ },
213
+ z.core.$strip
214
+ >;
215
+
216
+ /**
217
+ * Nominal brand the CLI discriminates on to enable the workbench build/deploy
218
+ * codepath. Registered via `Symbol.for` so the marker survives module-realm
219
+ * boundaries — `@sanity/cli-core` re-derives the same global symbol with
220
+ * `Symbol.for` rather than importing it, so it stays internal to this module.
221
+ */
222
+ declare const WORKBENCH_APP: unique symbol;
223
+
224
+ /**
225
+ * A branded app as the CLI reads it — the full schema shape, including the
226
+ * internal fields `DefineAppInput` omits. Schema-derived so the narrowing
227
+ * can't drift from what the schema validates.
228
+ * @public
229
+ */
230
+ declare type WorkbenchApp = DefineAppResult &
231
+ z.output<typeof DefineAppInputSchema>;
232
+
233
+ /** The workbench extension of the shared target; serializes into `--json` as-is. */
234
+ declare type WorkbenchUndeployTarget =
235
+ | (UndeployApplicationTarget & {
236
+ /** Interfaces (views and services) registered by the application. */
237
+ interfaces: DeployedExpose[];
238
+ })
239
+ | (UndeployConfigTarget & {
240
+ /** The deployed config snapshots an undeploy deletes. */
241
+ configs: {
242
+ createdAt: string | null;
243
+ deployedBy: string | null;
244
+ id: string;
245
+ }[];
246
+ });
247
+
248
+ export {};
@@ -0,0 +1,3 @@
1
+ export { createWorkbenchUndeployAdapter } from '../actions/undeploy/workbenchUndeployAdapter.js';
2
+
3
+ //# sourceMappingURL=undeploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/_exports/undeploy.ts"],"sourcesContent":["export {createWorkbenchUndeployAdapter} from '../actions/undeploy/workbenchUndeployAdapter.js'\n"],"names":["createWorkbenchUndeployAdapter"],"mappings":"AAAA,SAAQA,8BAA8B,QAAO,kDAAiD"}
@@ -1,4 +1,4 @@
1
- import { installationConfigArtifacts } from './configs/artifact.js';
1
+ import { configArtifacts } from './configs/artifact.js';
2
2
  import { serviceArtifacts } from './services/artifact.js';
3
3
  import { viewArtifacts } from './views/artifact.js';
4
4
  /**
@@ -23,7 +23,7 @@ import { viewArtifacts } from './views/artifact.js';
23
23
  return [
24
24
  ...viewArtifacts(exposes.views ?? []),
25
25
  ...serviceArtifacts(exposes.services ?? []),
26
- ...installationConfigArtifacts(exposes.installationConfig)
26
+ ...configArtifacts(exposes.config)
27
27
  ];
28
28
  }
29
29
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/build/artifact.ts"],"sourcesContent":["import {type WorkbenchExposes} from '../../resolveWorkbenchApp.js'\nimport {installationConfigArtifacts} from './configs/artifact.js'\nimport {serviceArtifacts} from './services/artifact.js'\nimport {viewArtifacts} from './views/artifact.js'\n\n/**\n * What a {@link GeneratedArtifact.source} builder receives from the build — the\n * one thing it can't compute on its own, since only the build knows where the\n * runtime dir sits relative to the app's `src`.\n */\ninterface ArtifactContext {\n /** Import specifier for an app `src` file, relative to this artifact. */\n resolveImport: (src: string) => string\n}\n\n/**\n * One file the federation build generates into the runtime dir for a declared\n * interface. Each interface type — views, services — expands its declarations\n * into a flat list of these; the build then writes them and maps the ones the\n * host loads directly into the module-federation manifest.\n *\n * Adding an interface type is adding a builder that returns\n * `GeneratedArtifact[]` — the write loop and the expose mapping never change.\n */\nexport interface GeneratedArtifact {\n /** Path relative to the federation runtime dir, e.g. `views/feed/panel.js`. */\n path: string\n /** Build the file's contents. */\n source: (context: ArtifactContext) => string\n\n /**\n * Module-federation expose key when the host loads this artifact directly —\n * a view component `./views/feed/panel`, a service loader `./services/unread`.\n * Omitted for a file the host never loads on its own, like a worker bundle\n * (reached through its sibling loader).\n */\n expose?: string\n}\n\n/**\n * Map the artifacts the host loads directly (those with an `expose`) to their\n * runtime-dir paths, for the module-federation `exposes` field. `toExposePath`\n * turns a runtime-relative artifact path into the value federation wants — the\n * caller owns the runtime-dir location and any entry resolution.\n */\nexport function artifactExposes(\n artifacts: readonly GeneratedArtifact[],\n toExposePath: (artifactPath: string) => string,\n): Record<string, string> {\n const exposes: Record<string, string> = {}\n for (const artifact of artifacts) {\n if (artifact.expose) {\n exposes[artifact.expose] = toExposePath(artifact.path)\n }\n }\n return exposes\n}\n\n/**\n * Expand what the app exposes into the flat artifact set the federation build\n * writes — the single place that composes the per-type expanders, so the expose\n * mapping and the file writing read from one expansion.\n */\nexport function workbenchArtifacts(exposes: WorkbenchExposes): GeneratedArtifact[] {\n return [\n ...viewArtifacts(exposes.views ?? []),\n ...serviceArtifacts(exposes.services ?? []),\n ...installationConfigArtifacts(exposes.installationConfig),\n ]\n}\n"],"names":["installationConfigArtifacts","serviceArtifacts","viewArtifacts","artifactExposes","artifacts","toExposePath","exposes","artifact","expose","path","workbenchArtifacts","views","services","installationConfig"],"mappings":"AACA,SAAQA,2BAA2B,QAAO,wBAAuB;AACjE,SAAQC,gBAAgB,QAAO,yBAAwB;AACvD,SAAQC,aAAa,QAAO,sBAAqB;AAoCjD;;;;;CAKC,GACD,OAAO,SAASC,gBACdC,SAAuC,EACvCC,YAA8C;IAE9C,MAAMC,UAAkC,CAAC;IACzC,KAAK,MAAMC,YAAYH,UAAW;QAChC,IAAIG,SAASC,MAAM,EAAE;YACnBF,OAAO,CAACC,SAASC,MAAM,CAAC,GAAGH,aAAaE,SAASE,IAAI;QACvD;IACF;IACA,OAAOH;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASI,mBAAmBJ,OAAyB;IAC1D,OAAO;WACFJ,cAAcI,QAAQK,KAAK,IAAI,EAAE;WACjCV,iBAAiBK,QAAQM,QAAQ,IAAI,EAAE;WACvCZ,4BAA4BM,QAAQO,kBAAkB;KAC1D;AACH"}
1
+ {"version":3,"sources":["../../../src/actions/build/artifact.ts"],"sourcesContent":["import {type WorkbenchExposes} from '../../resolveWorkbenchApp.js'\nimport {configArtifacts} from './configs/artifact.js'\nimport {serviceArtifacts} from './services/artifact.js'\nimport {viewArtifacts} from './views/artifact.js'\n\n/**\n * What a {@link GeneratedArtifact.source} builder receives from the build — the\n * one thing it can't compute on its own, since only the build knows where the\n * runtime dir sits relative to the app's `src`.\n */\ninterface ArtifactContext {\n /** Import specifier for an app `src` file, relative to this artifact. */\n resolveImport: (src: string) => string\n}\n\n/**\n * One file the federation build generates into the runtime dir for a declared\n * interface. Each interface type — views, services — expands its declarations\n * into a flat list of these; the build then writes them and maps the ones the\n * host loads directly into the module-federation manifest.\n *\n * Adding an interface type is adding a builder that returns\n * `GeneratedArtifact[]` — the write loop and the expose mapping never change.\n */\nexport interface GeneratedArtifact {\n /** Path relative to the federation runtime dir, e.g. `views/feed/panel.js`. */\n path: string\n /** Build the file's contents. */\n source: (context: ArtifactContext) => string\n\n /**\n * Module-federation expose key when the host loads this artifact directly —\n * a view component `./views/feed/panel`, a service loader `./services/unread`.\n * Omitted for a file the host never loads on its own, like a worker bundle\n * (reached through its sibling loader).\n */\n expose?: string\n}\n\n/**\n * Map the artifacts the host loads directly (those with an `expose`) to their\n * runtime-dir paths, for the module-federation `exposes` field. `toExposePath`\n * turns a runtime-relative artifact path into the value federation wants — the\n * caller owns the runtime-dir location and any entry resolution.\n */\nexport function artifactExposes(\n artifacts: readonly GeneratedArtifact[],\n toExposePath: (artifactPath: string) => string,\n): Record<string, string> {\n const exposes: Record<string, string> = {}\n for (const artifact of artifacts) {\n if (artifact.expose) {\n exposes[artifact.expose] = toExposePath(artifact.path)\n }\n }\n return exposes\n}\n\n/**\n * Expand what the app exposes into the flat artifact set the federation build\n * writes — the single place that composes the per-type expanders, so the expose\n * mapping and the file writing read from one expansion.\n */\nexport function workbenchArtifacts(exposes: WorkbenchExposes): GeneratedArtifact[] {\n return [\n ...viewArtifacts(exposes.views ?? []),\n ...serviceArtifacts(exposes.services ?? []),\n ...configArtifacts(exposes.config),\n ]\n}\n"],"names":["configArtifacts","serviceArtifacts","viewArtifacts","artifactExposes","artifacts","toExposePath","exposes","artifact","expose","path","workbenchArtifacts","views","services","config"],"mappings":"AACA,SAAQA,eAAe,QAAO,wBAAuB;AACrD,SAAQC,gBAAgB,QAAO,yBAAwB;AACvD,SAAQC,aAAa,QAAO,sBAAqB;AAoCjD;;;;;CAKC,GACD,OAAO,SAASC,gBACdC,SAAuC,EACvCC,YAA8C;IAE9C,MAAMC,UAAkC,CAAC;IACzC,KAAK,MAAMC,YAAYH,UAAW;QAChC,IAAIG,SAASC,MAAM,EAAE;YACnBF,OAAO,CAACC,SAASC,MAAM,CAAC,GAAGH,aAAaE,SAASE,IAAI;QACvD;IACF;IACA,OAAOH;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASI,mBAAmBJ,OAAyB;IAC1D,OAAO;WACFJ,cAAcI,QAAQK,KAAK,IAAI,EAAE;WACjCV,iBAAiBK,QAAQM,QAAQ,IAAI,EAAE;WACvCZ,gBAAgBM,QAAQO,MAAM;KAClC;AACH"}
@@ -1,12 +1,12 @@
1
- import { INSTALLATION_CONFIG_TYPE, MEDIA_LIBRARY_INSTALLATION_CONFIG_CONTRACT_VERSION } from '../../../contract.js';
1
+ import { INSTALLATION_CONFIG_TYPE, MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION } from '../../../contract.js';
2
2
  const CONFIGS_DIR_NAME = 'configs';
3
- /** Expand the installation config into one federation module aggregating all fields, so the host imports one live config value. */ export function installationConfigArtifacts(config) {
3
+ /** Expand the config into one federation module aggregating all fields, so the host imports one live config value. */ export function configArtifacts(config) {
4
4
  if (!config) return [];
5
5
  return [
6
6
  {
7
7
  expose: `./${CONFIGS_DIR_NAME}/${INSTALLATION_CONFIG_TYPE}`,
8
8
  path: `${CONFIGS_DIR_NAME}/${INSTALLATION_CONFIG_TYPE}.js`,
9
- source: ({ resolveImport })=>mediaLibraryInstallationConfigSource({
9
+ source: ({ resolveImport })=>mediaLibraryConfigSource({
10
10
  config,
11
11
  resolveImport
12
12
  })
@@ -17,7 +17,7 @@ const CONFIGS_DIR_NAME = 'configs';
17
17
  * Emits `export const config`: each field's serializable `{name, title, public}`
18
18
  * plus its live `defineField` value, the one thing the wire can't carry.
19
19
  * `appType` stays off the module — the host assigns it from the wire record.
20
- */ function mediaLibraryInstallationConfigSource(input) {
20
+ */ function mediaLibraryConfigSource(input) {
21
21
  const { config, resolveImport } = input;
22
22
  const imports = config.fields.map((field, index)=>`import field_${index} from ${JSON.stringify(resolveImport(field.src))}`).join('\n');
23
23
  const entries = config.fields.map((field, index)=>` {name: ${JSON.stringify(field.name)}, title: ${JSON.stringify(field.title)}, ` + `public: ${JSON.stringify(Boolean(field.public))}, config: field_${index}},`).join('\n');
@@ -27,7 +27,7 @@ const CONFIGS_DIR_NAME = 'configs';
27
27
  ${imports}
28
28
 
29
29
  export const type = ${JSON.stringify(INSTALLATION_CONFIG_TYPE)}
30
- export const version = ${MEDIA_LIBRARY_INSTALLATION_CONFIG_CONTRACT_VERSION}
30
+ export const version = ${MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION}
31
31
  export const config = {
32
32
  fields: [
33
33
  ${entries}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/actions/build/configs/artifact.ts"],"sourcesContent":["import {\n INSTALLATION_CONFIG_TYPE,\n MEDIA_LIBRARY_INSTALLATION_CONFIG_CONTRACT_VERSION,\n} from '../../../contract.js'\nimport {type GeneratedArtifact} from '../artifact.js'\n\nconst CONFIGS_DIR_NAME = 'configs'\n\n/**\n * The installation config to generate a module for.\n * @internal\n */\nexport interface ConfigArtifact {\n fields: {name: string; public?: boolean; src: string; title: string}[]\n}\n\n/** Expand the installation config into one federation module aggregating all fields, so the host imports one live config value. */\nexport function installationConfigArtifacts(\n config: ConfigArtifact | undefined,\n): GeneratedArtifact[] {\n if (!config) return []\n return [\n {\n expose: `./${CONFIGS_DIR_NAME}/${INSTALLATION_CONFIG_TYPE}`,\n path: `${CONFIGS_DIR_NAME}/${INSTALLATION_CONFIG_TYPE}.js`,\n source: ({resolveImport}) => mediaLibraryInstallationConfigSource({config, resolveImport}),\n },\n ]\n}\n\n/**\n * Emits `export const config`: each field's serializable `{name, title, public}`\n * plus its live `defineField` value, the one thing the wire can't carry.\n * `appType` stays off the module — the host assigns it from the wire record.\n */\nfunction mediaLibraryInstallationConfigSource(input: {\n config: ConfigArtifact\n resolveImport: (src: string) => string\n}): string {\n const {config, resolveImport} = input\n const imports = config.fields\n .map((field, index) => `import field_${index} from ${JSON.stringify(resolveImport(field.src))}`)\n .join('\\n')\n const entries = config.fields\n .map(\n (field, index) =>\n ` {name: ${JSON.stringify(field.name)}, title: ${JSON.stringify(field.title)}, ` +\n `public: ${JSON.stringify(Boolean(field.public))}, config: field_${index}},`,\n )\n .join('\\n')\n return `\\\n// This file is auto-generated on 'sanity build' / 'sanity dev'\n// Modifications to this file are automatically discarded\n${imports}\n\nexport const type = ${JSON.stringify(INSTALLATION_CONFIG_TYPE)}\nexport const version = ${MEDIA_LIBRARY_INSTALLATION_CONFIG_CONTRACT_VERSION}\nexport const config = {\n fields: [\n${entries}\n ],\n}\n\nif (import.meta.hot) {\n // A config is data, not a rendered island with a live root to remount —\n // self-accept so a field edit swaps the module in place; the host re-reads it.\n import.meta.hot.accept()\n}\n`\n}\n"],"names":["INSTALLATION_CONFIG_TYPE","MEDIA_LIBRARY_INSTALLATION_CONFIG_CONTRACT_VERSION","CONFIGS_DIR_NAME","installationConfigArtifacts","config","expose","path","source","resolveImport","mediaLibraryInstallationConfigSource","input","imports","fields","map","field","index","JSON","stringify","src","join","entries","name","title","Boolean","public"],"mappings":"AAAA,SACEA,wBAAwB,EACxBC,kDAAkD,QAC7C,uBAAsB;AAG7B,MAAMC,mBAAmB;AAUzB,iIAAiI,GACjI,OAAO,SAASC,4BACdC,MAAkC;IAElC,IAAI,CAACA,QAAQ,OAAO,EAAE;IACtB,OAAO;QACL;YACEC,QAAQ,CAAC,EAAE,EAAEH,iBAAiB,CAAC,EAAEF,0BAA0B;YAC3DM,MAAM,GAAGJ,iBAAiB,CAAC,EAAEF,yBAAyB,GAAG,CAAC;YAC1DO,QAAQ,CAAC,EAACC,aAAa,EAAC,GAAKC,qCAAqC;oBAACL;oBAAQI;gBAAa;QAC1F;KACD;AACH;AAEA;;;;CAIC,GACD,SAASC,qCAAqCC,KAG7C;IACC,MAAM,EAACN,MAAM,EAAEI,aAAa,EAAC,GAAGE;IAChC,MAAMC,UAAUP,OAAOQ,MAAM,CAC1BC,GAAG,CAAC,CAACC,OAAOC,QAAU,CAAC,aAAa,EAAEA,MAAM,MAAM,EAAEC,KAAKC,SAAS,CAACT,cAAcM,MAAMI,GAAG,IAAI,EAC9FC,IAAI,CAAC;IACR,MAAMC,UAAUhB,OAAOQ,MAAM,CAC1BC,GAAG,CACF,CAACC,OAAOC,QACN,CAAC,WAAW,EAAEC,KAAKC,SAAS,CAACH,MAAMO,IAAI,EAAE,SAAS,EAAEL,KAAKC,SAAS,CAACH,MAAMQ,KAAK,EAAE,EAAE,CAAC,GACnF,CAAC,QAAQ,EAAEN,KAAKC,SAAS,CAACM,QAAQT,MAAMU,MAAM,GAAG,gBAAgB,EAAET,MAAM,EAAE,CAAC,EAE/EI,IAAI,CAAC;IACR,OAAO,CAAC;;;AAGV,EAAER,QAAQ;;oBAEU,EAAEK,KAAKC,SAAS,CAACjB,0BAA0B;uBACxC,EAAEC,mDAAmD;;;AAG5E,EAAEmB,QAAQ;;;;;;;;;AASV,CAAC;AACD"}
1
+ {"version":3,"sources":["../../../../src/actions/build/configs/artifact.ts"],"sourcesContent":["import {INSTALLATION_CONFIG_TYPE, MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION} from '../../../contract.js'\nimport {type GeneratedArtifact} from '../artifact.js'\n\nconst CONFIGS_DIR_NAME = 'configs'\n\n/**\n * The config to generate a module for.\n * @internal\n */\nexport interface ConfigArtifact {\n fields: {name: string; public?: boolean; src: string; title: string}[]\n}\n\n/** Expand the config into one federation module aggregating all fields, so the host imports one live config value. */\nexport function configArtifacts(config: ConfigArtifact | undefined): GeneratedArtifact[] {\n if (!config) return []\n return [\n {\n expose: `./${CONFIGS_DIR_NAME}/${INSTALLATION_CONFIG_TYPE}`,\n path: `${CONFIGS_DIR_NAME}/${INSTALLATION_CONFIG_TYPE}.js`,\n source: ({resolveImport}) => mediaLibraryConfigSource({config, resolveImport}),\n },\n ]\n}\n\n/**\n * Emits `export const config`: each field's serializable `{name, title, public}`\n * plus its live `defineField` value, the one thing the wire can't carry.\n * `appType` stays off the module — the host assigns it from the wire record.\n */\nfunction mediaLibraryConfigSource(input: {\n config: ConfigArtifact\n resolveImport: (src: string) => string\n}): string {\n const {config, resolveImport} = input\n const imports = config.fields\n .map((field, index) => `import field_${index} from ${JSON.stringify(resolveImport(field.src))}`)\n .join('\\n')\n const entries = config.fields\n .map(\n (field, index) =>\n ` {name: ${JSON.stringify(field.name)}, title: ${JSON.stringify(field.title)}, ` +\n `public: ${JSON.stringify(Boolean(field.public))}, config: field_${index}},`,\n )\n .join('\\n')\n return `\\\n// This file is auto-generated on 'sanity build' / 'sanity dev'\n// Modifications to this file are automatically discarded\n${imports}\n\nexport const type = ${JSON.stringify(INSTALLATION_CONFIG_TYPE)}\nexport const version = ${MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION}\nexport const config = {\n fields: [\n${entries}\n ],\n}\n\nif (import.meta.hot) {\n // A config is data, not a rendered island with a live root to remount —\n // self-accept so a field edit swaps the module in place; the host re-reads it.\n import.meta.hot.accept()\n}\n`\n}\n"],"names":["INSTALLATION_CONFIG_TYPE","MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION","CONFIGS_DIR_NAME","configArtifacts","config","expose","path","source","resolveImport","mediaLibraryConfigSource","input","imports","fields","map","field","index","JSON","stringify","src","join","entries","name","title","Boolean","public"],"mappings":"AAAA,SAAQA,wBAAwB,EAAEC,qCAAqC,QAAO,uBAAsB;AAGpG,MAAMC,mBAAmB;AAUzB,oHAAoH,GACpH,OAAO,SAASC,gBAAgBC,MAAkC;IAChE,IAAI,CAACA,QAAQ,OAAO,EAAE;IACtB,OAAO;QACL;YACEC,QAAQ,CAAC,EAAE,EAAEH,iBAAiB,CAAC,EAAEF,0BAA0B;YAC3DM,MAAM,GAAGJ,iBAAiB,CAAC,EAAEF,yBAAyB,GAAG,CAAC;YAC1DO,QAAQ,CAAC,EAACC,aAAa,EAAC,GAAKC,yBAAyB;oBAACL;oBAAQI;gBAAa;QAC9E;KACD;AACH;AAEA;;;;CAIC,GACD,SAASC,yBAAyBC,KAGjC;IACC,MAAM,EAACN,MAAM,EAAEI,aAAa,EAAC,GAAGE;IAChC,MAAMC,UAAUP,OAAOQ,MAAM,CAC1BC,GAAG,CAAC,CAACC,OAAOC,QAAU,CAAC,aAAa,EAAEA,MAAM,MAAM,EAAEC,KAAKC,SAAS,CAACT,cAAcM,MAAMI,GAAG,IAAI,EAC9FC,IAAI,CAAC;IACR,MAAMC,UAAUhB,OAAOQ,MAAM,CAC1BC,GAAG,CACF,CAACC,OAAOC,QACN,CAAC,WAAW,EAAEC,KAAKC,SAAS,CAACH,MAAMO,IAAI,EAAE,SAAS,EAAEL,KAAKC,SAAS,CAACH,MAAMQ,KAAK,EAAE,EAAE,CAAC,GACnF,CAAC,QAAQ,EAAEN,KAAKC,SAAS,CAACM,QAAQT,MAAMU,MAAM,GAAG,gBAAgB,EAAET,MAAM,EAAE,CAAC,EAE/EI,IAAI,CAAC;IACR,OAAO,CAAC;;;AAGV,EAAER,QAAQ;;oBAEU,EAAEK,KAAKC,SAAS,CAACjB,0BAA0B;uBACxC,EAAEC,sCAAsC;;;AAG/D,EAAEmB,QAAQ;;;;;;;;;AASV,CAAC;AACD"}
@@ -48,8 +48,13 @@ import { sanityFederationRuntime } from './plugins/plugin-sanity-federation-runt
48
48
  isApp: false,
49
49
  studioConfigPath: options.studioConfigPath
50
50
  };
51
+ // A workbench remote can also serve itself standalone. When the remote flag is
52
+ // set (and there's an `./App` to mount — never for a dock-only app), build the
53
+ // SPA client environment from the runtime bootstrap cli-build writes.
54
+ const clientInput = process.env.SANITY_INTERNAL_IS_WORKBENCH_REMOTE === 'true' && exposesApp ? path.join(workDir, '.sanity', 'runtime', 'app.js') : undefined;
51
55
  return [
52
56
  sanityEnvironmentPlugin({
57
+ clientInput,
53
58
  input: entryPath
54
59
  }),
55
60
  sanityFederationRuntime(runtimeOptions),
@@ -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 return [\n sanityEnvironmentPlugin({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","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,OAAO;QACL5B,wBAAwB;YAAC6B,OAAOX;QAAS;QACzChB,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 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 // A workbench remote can also serve itself standalone. When the remote flag is\n // set (and there's an `./App` to mount — never for a dock-only app), build the\n // SPA client environment from the runtime bootstrap cli-build writes.\n const clientInput =\n process.env.SANITY_INTERNAL_IS_WORKBENCH_REMOTE === 'true' && exposesApp\n ? path.join(workDir, '.sanity', 'runtime', 'app.js')\n : 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","env","SANITY_INTERNAL_IS_WORKBENCH_REMOTE","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,+EAA+E;IAC/E,+EAA+E;IAC/E,sEAAsE;IACtE,MAAMC,cACJnB,QAAQoB,GAAG,CAACC,mCAAmC,KAAK,UAAUT,aAC1D5B,KAAKsC,IAAI,CAACvB,SAAS,WAAW,WAAW,YACzCgB;IAEN,OAAO;QACLzB,wBAAwB;YAAC6B;YAAaI,OAAOf;QAAS;QACtDhB,wBAAwByB;QACxB1B,yBAAyB;YAACkB;QAAS;QACnCpB,uBAAuB;YAACM,SAASqB;YAAmBpB;QAAI;KACzD;AACH,EAAC"}
@@ -2,7 +2,7 @@
2
2
  * Bake the app's bus identity into its bundle: `@sanity/runtime` reads
3
3
  * `__SANITY_APP_ID__` where it connects. `define` covers everything the
4
4
  * pipeline transforms (all of a production build, and dev-served source); the
5
- * esbuild define covers dev's pre-bundled dependencies, which skip Vite's
5
+ * rolldown define covers dev's pre-bundled dependencies, which skip Vite's
6
6
  * define transform.
7
7
  */ export function sanityAppId(appId) {
8
8
  const define = {
@@ -12,8 +12,10 @@
12
12
  config: ()=>({
13
13
  define,
14
14
  optimizeDeps: {
15
- esbuildOptions: {
16
- define
15
+ rolldownOptions: {
16
+ transform: {
17
+ define
18
+ }
17
19
  }
18
20
  }
19
21
  }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/actions/build/vite/plugins/plugin-sanity-app-id.ts"],"sourcesContent":["import {type Plugin} from 'vite'\n\n/**\n * Bake the app's bus identity into its bundle: `@sanity/runtime` reads\n * `__SANITY_APP_ID__` where it connects. `define` covers everything the\n * pipeline transforms (all of a production build, and dev-served source); the\n * esbuild define covers dev's pre-bundled dependencies, which skip Vite's\n * define transform.\n */\nexport function sanityAppId(appId: string): Plugin {\n const define = {__SANITY_APP_ID__: JSON.stringify(appId)}\n return {\n config: () => ({define, optimizeDeps: {esbuildOptions: {define}}}),\n name: 'sanity/workbench/app-id',\n }\n}\n"],"names":["sanityAppId","appId","define","__SANITY_APP_ID__","JSON","stringify","config","optimizeDeps","esbuildOptions","name"],"mappings":"AAEA;;;;;;CAMC,GACD,OAAO,SAASA,YAAYC,KAAa;IACvC,MAAMC,SAAS;QAACC,mBAAmBC,KAAKC,SAAS,CAACJ;IAAM;IACxD,OAAO;QACLK,QAAQ,IAAO,CAAA;gBAACJ;gBAAQK,cAAc;oBAACC,gBAAgB;wBAACN;oBAAM;gBAAC;YAAC,CAAA;QAChEO,MAAM;IACR;AACF"}
1
+ {"version":3,"sources":["../../../../../src/actions/build/vite/plugins/plugin-sanity-app-id.ts"],"sourcesContent":["import {type Plugin} from 'vite'\n\n/**\n * Bake the app's bus identity into its bundle: `@sanity/runtime` reads\n * `__SANITY_APP_ID__` where it connects. `define` covers everything the\n * pipeline transforms (all of a production build, and dev-served source); the\n * rolldown define covers dev's pre-bundled dependencies, which skip Vite's\n * define transform.\n */\nexport function sanityAppId(appId: string): Plugin {\n const define = {__SANITY_APP_ID__: JSON.stringify(appId)}\n return {\n config: () => ({define, optimizeDeps: {rolldownOptions: {transform: {define}}}}),\n name: 'sanity/workbench/app-id',\n }\n}\n"],"names":["sanityAppId","appId","define","__SANITY_APP_ID__","JSON","stringify","config","optimizeDeps","rolldownOptions","transform","name"],"mappings":"AAEA;;;;;;CAMC,GACD,OAAO,SAASA,YAAYC,KAAa;IACvC,MAAMC,SAAS;QAACC,mBAAmBC,KAAKC,SAAS,CAACJ;IAAM;IACxD,OAAO;QACLK,QAAQ,IAAO,CAAA;gBAACJ;gBAAQK,cAAc;oBAACC,iBAAiB;wBAACC,WAAW;4BAACP;wBAAM;oBAAC;gBAAC;YAAC,CAAA;QAC9EQ,MAAM;IACR;AACF"}
@@ -1,20 +1,44 @@
1
1
  import { FEDERATION_DIR_NAME } from '../constants.js';
2
2
  export function sanityEnvironmentPlugin(options) {
3
+ const { clientInput, input } = options;
3
4
  return {
4
5
  config () {
5
6
  return {
6
7
  builder: {
7
8
  async buildApp (builder) {
9
+ // `emptyOutDir` is false on both environments and the CLI clears
10
+ // `dist` once up-front, so the SPA and federation outputs coexist
11
+ // without either build wiping the other's files.
12
+ if (clientInput) {
13
+ await builder.build(builder.environments.client);
14
+ }
8
15
  await builder.build(builder.environments[FEDERATION_DIR_NAME]);
9
16
  }
10
17
  },
11
18
  environments: {
19
+ ...clientInput ? {
20
+ client: {
21
+ build: {
22
+ assetsDir: 'static',
23
+ copyPublicDir: false,
24
+ emptyOutDir: false,
25
+ outDir: `dist`,
26
+ rolldownOptions: {
27
+ input: {
28
+ sanity: clientInput
29
+ }
30
+ }
31
+ },
32
+ consumer: 'client'
33
+ }
34
+ } : {},
12
35
  [FEDERATION_DIR_NAME]: {
13
36
  build: {
14
37
  copyPublicDir: false,
38
+ emptyOutDir: false,
15
39
  outDir: `dist`,
16
- rollupOptions: {
17
- input: options.input
40
+ rolldownOptions: {
41
+ input
18
42
  }
19
43
  },
20
44
  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\nexport function sanityEnvironmentPlugin(options: EnvironmentOptions): Plugin {\n return {\n config() {\n return {\n builder: {\n async buildApp(builder) {\n await builder.build(builder.environments[FEDERATION_DIR_NAME])\n },\n },\n environments: {\n [FEDERATION_DIR_NAME]: {\n build: {\n copyPublicDir: false,\n outDir: `dist`,\n rollupOptions: {input: options.input},\n },\n consumer: 'client',\n },\n },\n }\n },\n name: 'sanity/environment',\n }\n}\n"],"names":["FEDERATION_DIR_NAME","sanityEnvironmentPlugin","options","config","builder","buildApp","build","environments","copyPublicDir","outDir","rollupOptions","input","consumer","name"],"mappings":"AAEA,SAAQA,mBAAmB,QAAO,kBAAiB;AAMnD,OAAO,SAASC,wBAAwBC,OAA2B;IACjE,OAAO;QACLC;YACE,OAAO;gBACLC,SAAS;oBACP,MAAMC,UAASD,OAAO;wBACpB,MAAMA,QAAQE,KAAK,CAACF,QAAQG,YAAY,CAACP,oBAAoB;oBAC/D;gBACF;gBACAO,cAAc;oBACZ,CAACP,oBAAoB,EAAE;wBACrBM,OAAO;4BACLE,eAAe;4BACfC,QAAQ,CAAC,IAAI,CAAC;4BACdC,eAAe;gCAACC,OAAOT,QAAQS,KAAK;4BAAA;wBACtC;wBACAC,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 {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 * Omitted for a dock-only app or when the workbench-remote SPA is disabled.\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 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;4BACLI,eAAe;4BACfC,aAAa;4BACbC,QAAQ,CAAC,IAAI,CAAC;4BACdC,iBAAiB;gCAACX;4BAAK;wBACzB;wBACAa,UAAU;oBACZ;gBACF;YACF;QACF;QACAC,MAAM;IACR;AACF"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * The interface records deploy sends: the app view (only when `exposesAppView`),
3
+ * every view, and every service.
4
+ * @internal
5
+ */ export function buildExposes(exposes, { appName, appTitle, exposesAppView, version }) {
6
+ const toRecord = (prefix, decl)=>({
7
+ moduleId: `${prefix}/${decl.name}`,
8
+ name: decl.name,
9
+ title: decl.title ?? decl.name,
10
+ type: decl.type,
11
+ version
12
+ });
13
+ const records = [];
14
+ if (exposesAppView) {
15
+ records.push({
16
+ moduleId: 'App',
17
+ name: appName,
18
+ title: appTitle,
19
+ type: 'app',
20
+ version
21
+ });
22
+ }
23
+ for (const view of exposes.views ?? [])records.push(toRecord('views', view));
24
+ for (const service of exposes.services ?? [])records.push(toRecord('services', service));
25
+ return records;
26
+ }
27
+ const label = (item)=>item.title === item.name ? item.name : `${item.title} (${item.name})`;
28
+ /**
29
+ * One `Title (name): src` report line per declared entry point.
30
+ * @internal
31
+ */ export function summarizeExposeGroup(heading, items) {
32
+ return `${heading}:\n${items.map((item)=>` ${label(item)}: ${item.src}`).join('\n')}`;
33
+ }
34
+ /**
35
+ * The deploy summary of an app's exposes: the structured records (for `--json`)
36
+ * and one report line per non-empty group (for the human report).
37
+ * @internal
38
+ */ export function summarizeExposes({ services, views }) {
39
+ const toExpose = (decl)=>({
40
+ name: decl.name,
41
+ src: decl.src,
42
+ title: decl.title ?? decl.name,
43
+ type: decl.type
44
+ });
45
+ const viewExposes = (views ?? []).map((view)=>toExpose(view));
46
+ const serviceExposes = (services ?? []).map((service)=>toExpose(service));
47
+ const lines = [];
48
+ if (viewExposes.length > 0) lines.push(summarizeExposeGroup('Views', viewExposes));
49
+ if (serviceExposes.length > 0) lines.push(summarizeExposeGroup('Services', serviceExposes));
50
+ return {
51
+ exposes: [
52
+ ...viewExposes,
53
+ ...serviceExposes
54
+ ],
55
+ lines
56
+ };
57
+ }
58
+
59
+ //# sourceMappingURL=buildExposes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/deploy/buildExposes.ts"],"sourcesContent":["import {type WorkbenchExposes} from '../../resolveWorkbenchApp.js'\nimport {type BrettInterface} from '../../services/applications.js'\n\ninterface BuildExposesContext {\n appName: string\n appTitle: string\n /** Whether the build exposes the app view (`./App`) — apps with an `entry`, and every studio. */\n exposesAppView: boolean\n version: string\n}\n\n/**\n * The interface records deploy sends: the app view (only when `exposesAppView`),\n * every view, and every service.\n * @internal\n */\nexport function buildExposes(\n exposes: WorkbenchExposes,\n {appName, appTitle, exposesAppView, version}: BuildExposesContext,\n): BrettInterface[] {\n const toRecord = (\n prefix: string,\n decl: {name: string; title?: string; type: string},\n ): BrettInterface => ({\n moduleId: `${prefix}/${decl.name}`,\n name: decl.name,\n title: decl.title ?? decl.name,\n type: decl.type,\n version,\n })\n\n const records: BrettInterface[] = []\n if (exposesAppView) {\n records.push({moduleId: 'App', name: appName, title: appTitle, type: 'app', version})\n }\n for (const view of exposes.views ?? []) records.push(toRecord('views', view))\n for (const service of exposes.services ?? []) records.push(toRecord('services', service))\n return records\n}\n\n/** A view or service as the deploy report and `--json` output surface it. */\nexport interface DeployedExpose {\n name: string\n src: string\n title: string\n type: string\n}\n\nconst label = (item: {name: string; title: string}) =>\n item.title === item.name ? item.name : `${item.title} (${item.name})`\n\n/**\n * One `Title (name): src` report line per declared entry point.\n * @internal\n */\nexport function summarizeExposeGroup(\n heading: string,\n items: readonly {name: string; src: string; title: string}[],\n): string {\n return `${heading}:\\n${items.map((item) => ` ${label(item)}: ${item.src}`).join('\\n')}`\n}\n\n/**\n * The deploy summary of an app's exposes: the structured records (for `--json`)\n * and one report line per non-empty group (for the human report).\n * @internal\n */\nexport function summarizeExposes({services, views}: WorkbenchExposes): {\n exposes: DeployedExpose[]\n lines: string[]\n} {\n const toExpose = (decl: {\n name: string\n src: string\n title?: string\n type: string\n }): DeployedExpose => ({\n name: decl.name,\n src: decl.src,\n title: decl.title ?? decl.name,\n type: decl.type,\n })\n const viewExposes = (views ?? []).map((view) => toExpose(view))\n const serviceExposes = (services ?? []).map((service) => toExpose(service))\n\n const lines: string[] = []\n if (viewExposes.length > 0) lines.push(summarizeExposeGroup('Views', viewExposes))\n if (serviceExposes.length > 0) lines.push(summarizeExposeGroup('Services', serviceExposes))\n return {exposes: [...viewExposes, ...serviceExposes], lines}\n}\n"],"names":["buildExposes","exposes","appName","appTitle","exposesAppView","version","toRecord","prefix","decl","moduleId","name","title","type","records","push","view","views","service","services","label","item","summarizeExposeGroup","heading","items","map","src","join","summarizeExposes","toExpose","viewExposes","serviceExposes","lines","length"],"mappings":"AAWA;;;;CAIC,GACD,OAAO,SAASA,aACdC,OAAyB,EACzB,EAACC,OAAO,EAAEC,QAAQ,EAAEC,cAAc,EAAEC,OAAO,EAAsB;IAEjE,MAAMC,WAAW,CACfC,QACAC,OACoB,CAAA;YACpBC,UAAU,GAAGF,OAAO,CAAC,EAAEC,KAAKE,IAAI,EAAE;YAClCA,MAAMF,KAAKE,IAAI;YACfC,OAAOH,KAAKG,KAAK,IAAIH,KAAKE,IAAI;YAC9BE,MAAMJ,KAAKI,IAAI;YACfP;QACF,CAAA;IAEA,MAAMQ,UAA4B,EAAE;IACpC,IAAIT,gBAAgB;QAClBS,QAAQC,IAAI,CAAC;YAACL,UAAU;YAAOC,MAAMR;YAASS,OAAOR;YAAUS,MAAM;YAAOP;QAAO;IACrF;IACA,KAAK,MAAMU,QAAQd,QAAQe,KAAK,IAAI,EAAE,CAAEH,QAAQC,IAAI,CAACR,SAAS,SAASS;IACvE,KAAK,MAAME,WAAWhB,QAAQiB,QAAQ,IAAI,EAAE,CAAEL,QAAQC,IAAI,CAACR,SAAS,YAAYW;IAChF,OAAOJ;AACT;AAUA,MAAMM,QAAQ,CAACC,OACbA,KAAKT,KAAK,KAAKS,KAAKV,IAAI,GAAGU,KAAKV,IAAI,GAAG,GAAGU,KAAKT,KAAK,CAAC,EAAE,EAAES,KAAKV,IAAI,CAAC,CAAC,CAAC;AAEvE;;;CAGC,GACD,OAAO,SAASW,qBACdC,OAAe,EACfC,KAA4D;IAE5D,OAAO,GAAGD,QAAQ,GAAG,EAAEC,MAAMC,GAAG,CAAC,CAACJ,OAAS,CAAC,EAAE,EAAED,MAAMC,MAAM,EAAE,EAAEA,KAAKK,GAAG,EAAE,EAAEC,IAAI,CAAC,OAAO;AAC1F;AAEA;;;;CAIC,GACD,OAAO,SAASC,iBAAiB,EAACT,QAAQ,EAAEF,KAAK,EAAmB;IAIlE,MAAMY,WAAW,CAACpB,OAKK,CAAA;YACrBE,MAAMF,KAAKE,IAAI;YACfe,KAAKjB,KAAKiB,GAAG;YACbd,OAAOH,KAAKG,KAAK,IAAIH,KAAKE,IAAI;YAC9BE,MAAMJ,KAAKI,IAAI;QACjB,CAAA;IACA,MAAMiB,cAAc,AAACb,CAAAA,SAAS,EAAE,AAAD,EAAGQ,GAAG,CAAC,CAACT,OAASa,SAASb;IACzD,MAAMe,iBAAiB,AAACZ,CAAAA,YAAY,EAAE,AAAD,EAAGM,GAAG,CAAC,CAACP,UAAYW,SAASX;IAElE,MAAMc,QAAkB,EAAE;IAC1B,IAAIF,YAAYG,MAAM,GAAG,GAAGD,MAAMjB,IAAI,CAACO,qBAAqB,SAASQ;IACrE,IAAIC,eAAeE,MAAM,GAAG,GAAGD,MAAMjB,IAAI,CAACO,qBAAqB,YAAYS;IAC3E,OAAO;QAAC7B,SAAS;eAAI4B;eAAgBC;SAAe;QAAEC;IAAK;AAC7D"}
@@ -2,9 +2,10 @@ import { stat } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  /**
4
4
  * Throws unless `sourceDir` is a directory holding a federation build.
5
- * Workbench builds emit a module-federation remote instead of a static SPA,
6
- * so the usual `index.html` contract doesn't apply — `mf-manifest.json` is the
7
- * marker that `sanity build` produced a federation build.
5
+ * A workbench build always emits a module-federation remote, and may
6
+ * additionally emit a standalone `index.html` SPA (workbench remotes). Either
7
+ * way `mf-manifest.json` is the reliable marker that `sanity build` produced a
8
+ * federation build, so that — not `index.html` — is what we check for.
8
9
  */ export async function checkBuiltOutput(sourceDir) {
9
10
  try {
10
11
  const stats = await stat(sourceDir);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/checkBuiltOutput.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {join} from 'node:path'\n\n/**\n * Throws unless `sourceDir` is a directory holding a federation build.\n * Workbench builds emit a module-federation remote instead of a static SPA,\n * so the usual `index.html` contract doesn't apply `mf-manifest.json` is the\n * marker that `sanity build` produced a federation build.\n */\nexport async function checkBuiltOutput(sourceDir: string): Promise<void> {\n try {\n const stats = await stat(sourceDir)\n if (!stats.isDirectory()) {\n throw new Error(`\"${sourceDir}\" is not a directory`)\n }\n } catch (err) {\n throw err.code === 'ENOENT' ? new Error(`Directory \"${sourceDir}\" does not exist`) : err\n }\n\n const manifestPath = join(sourceDir, 'mf-manifest.json')\n try {\n await stat(manifestPath)\n } catch (err) {\n throw err.code === 'ENOENT'\n ? new Error(\n `\"${manifestPath}\" does not exist. ` +\n 'The deploy directory must contain a federation build created with \"sanity build\".',\n )\n : err\n }\n}\n"],"names":["stat","join","checkBuiltOutput","sourceDir","stats","isDirectory","Error","err","code","manifestPath"],"mappings":"AAAA,SAAQA,IAAI,QAAO,mBAAkB;AACrC,SAAQC,IAAI,QAAO,YAAW;AAE9B;;;;;CAKC,GACD,OAAO,eAAeC,iBAAiBC,SAAiB;IACtD,IAAI;QACF,MAAMC,QAAQ,MAAMJ,KAAKG;QACzB,IAAI,CAACC,MAAMC,WAAW,IAAI;YACxB,MAAM,IAAIC,MAAM,CAAC,CAAC,EAAEH,UAAU,oBAAoB,CAAC;QACrD;IACF,EAAE,OAAOI,KAAK;QACZ,MAAMA,IAAIC,IAAI,KAAK,WAAW,IAAIF,MAAM,CAAC,WAAW,EAAEH,UAAU,gBAAgB,CAAC,IAAII;IACvF;IAEA,MAAME,eAAeR,KAAKE,WAAW;IACrC,IAAI;QACF,MAAMH,KAAKS;IACb,EAAE,OAAOF,KAAK;QACZ,MAAMA,IAAIC,IAAI,KAAK,WACf,IAAIF,MACF,CAAC,CAAC,EAAEG,aAAa,kBAAkB,CAAC,GAClC,uFAEJF;IACN;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/checkBuiltOutput.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {join} from 'node:path'\n\n/**\n * Throws unless `sourceDir` is a directory holding a federation build.\n * A workbench build always emits a module-federation remote, and may\n * additionally emit a standalone `index.html` SPA (workbench remotes). Either\n * way `mf-manifest.json` is the reliable marker that `sanity build` produced a\n * federation build, so that — not `index.html` — is what we check for.\n */\nexport async function checkBuiltOutput(sourceDir: string): Promise<void> {\n try {\n const stats = await stat(sourceDir)\n if (!stats.isDirectory()) {\n throw new Error(`\"${sourceDir}\" is not a directory`)\n }\n } catch (err) {\n throw err.code === 'ENOENT' ? new Error(`Directory \"${sourceDir}\" does not exist`) : err\n }\n\n const manifestPath = join(sourceDir, 'mf-manifest.json')\n try {\n await stat(manifestPath)\n } catch (err) {\n throw err.code === 'ENOENT'\n ? new Error(\n `\"${manifestPath}\" does not exist. ` +\n 'The deploy directory must contain a federation build created with \"sanity build\".',\n )\n : err\n }\n}\n"],"names":["stat","join","checkBuiltOutput","sourceDir","stats","isDirectory","Error","err","code","manifestPath"],"mappings":"AAAA,SAAQA,IAAI,QAAO,mBAAkB;AACrC,SAAQC,IAAI,QAAO,YAAW;AAE9B;;;;;;CAMC,GACD,OAAO,eAAeC,iBAAiBC,SAAiB;IACtD,IAAI;QACF,MAAMC,QAAQ,MAAMJ,KAAKG;QACzB,IAAI,CAACC,MAAMC,WAAW,IAAI;YACxB,MAAM,IAAIC,MAAM,CAAC,CAAC,EAAEH,UAAU,oBAAoB,CAAC;QACrD;IACF,EAAE,OAAOI,KAAK;QACZ,MAAMA,IAAIC,IAAI,KAAK,WAAW,IAAIF,MAAM,CAAC,WAAW,EAAEH,UAAU,gBAAgB,CAAC,IAAII;IACvF;IAEA,MAAME,eAAeR,KAAKE,WAAW;IACrC,IAAI;QACF,MAAMH,KAAKS;IACb,EAAE,OAAOF,KAAK;QACZ,MAAMA,IAAIC,IAAI,KAAK,WACf,IAAIF,MACF,CAAC,CAAC,EAAEG,aAAa,kBAAkB,CAAC,GAClC,uFAEJF;IACN;AACF"}