@sanity/workbench-cli 1.1.3 → 1.3.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.
- package/dist/_exports/build.d.ts +81 -8
- package/dist/_exports/build.js.map +1 -1
- package/dist/_exports/deploy.d.ts +287 -12
- package/dist/_exports/deploy.js +4 -3
- package/dist/_exports/deploy.js.map +1 -1
- package/dist/_exports/dev.d.ts +25 -0
- package/dist/_exports/index.d.ts +85 -31
- package/dist/_exports/index.js +1 -11
- package/dist/_exports/index.js.map +1 -1
- package/dist/actions/build/artifact.js +8 -7
- package/dist/actions/build/artifact.js.map +1 -1
- package/dist/actions/build/configs/artifact.js +45 -0
- package/dist/actions/build/configs/artifact.js.map +1 -0
- package/dist/actions/build/vite/plugin.js +6 -14
- package/dist/actions/build/vite/plugin.js.map +1 -1
- package/dist/actions/build/vite/plugins/plugin-sanity-app-id.js +24 -0
- package/dist/actions/build/vite/plugins/plugin-sanity-app-id.js.map +1 -0
- package/dist/actions/build/vite/workbench-vite-plugins.js +8 -4
- package/dist/actions/build/vite/workbench-vite-plugins.js.map +1 -1
- package/dist/actions/deploy/apiVersion.js +5 -0
- package/dist/actions/deploy/apiVersion.js.map +1 -0
- package/dist/actions/deploy/buildExposes.js +56 -0
- package/dist/actions/deploy/buildExposes.js.map +1 -0
- package/dist/actions/deploy/checkBuiltOutput.js +25 -0
- package/dist/actions/deploy/checkBuiltOutput.js.map +1 -0
- package/dist/actions/deploy/deployConfig.js +90 -0
- package/dist/actions/deploy/deployConfig.js.map +1 -0
- package/dist/actions/deploy/deployWorkbenchApp.js +185 -0
- package/dist/actions/deploy/deployWorkbenchApp.js.map +1 -0
- package/dist/actions/deploy/getWorkbench.js +14 -25
- package/dist/actions/deploy/getWorkbench.js.map +1 -1
- package/dist/actions/deploy/viewDeployment.js +32 -0
- package/dist/actions/deploy/viewDeployment.js.map +1 -0
- package/dist/actions/dev/deriveInterfaces.js +63 -6
- package/dist/actions/dev/deriveInterfaces.js.map +1 -1
- package/dist/actions/dev/exposesSetId.js +69 -0
- package/dist/actions/dev/exposesSetId.js.map +1 -0
- package/dist/actions/dev/registry.js +27 -1
- package/dist/actions/dev/registry.js.map +1 -1
- package/dist/actions/dev/startDevManifestWatcher.js +2 -1
- package/dist/actions/dev/startDevManifestWatcher.js.map +1 -1
- package/dist/actions/dev/startDevServerRegistration.js +26 -11
- package/dist/actions/dev/startDevServerRegistration.js.map +1 -1
- package/dist/actions/dev/startWorkbenchDevServer.js +23 -5
- package/dist/actions/dev/startWorkbenchDevServer.js.map +1 -1
- package/dist/actions/dev/writeWorkbenchRuntime.js +4 -1
- package/dist/actions/dev/writeWorkbenchRuntime.js.map +1 -1
- package/dist/contract.js +43 -40
- package/dist/contract.js.map +1 -1
- package/dist/defineApp.js +60 -1
- package/dist/defineApp.js.map +1 -1
- package/dist/resolveWorkbenchApp.js +5 -1
- package/dist/resolveWorkbenchApp.js.map +1 -1
- package/package.json +7 -4
- package/dist/actions/dev/interfaceSetId.js +0 -51
- package/dist/actions/dev/interfaceSetId.js.map +0 -1
package/dist/_exports/index.d.ts
CHANGED
|
@@ -2,13 +2,14 @@ import { z } from "zod/mini";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* User-facing input for `unstable_defineApp`. Excludes the internal
|
|
5
|
-
* `applicationType`
|
|
6
|
-
* the public surface (Sanity-owned apps set
|
|
5
|
+
* `applicationType`, `isSingleton`, and `config` — validated by the
|
|
6
|
+
* schema but not part of the public surface (Sanity-owned apps set them via
|
|
7
|
+
* `@ts-expect-error`).
|
|
7
8
|
* @public
|
|
8
9
|
*/
|
|
9
10
|
export declare type DefineAppInput = Omit<
|
|
10
11
|
z.output<typeof DefineAppInputSchema>,
|
|
11
|
-
"applicationType"
|
|
12
|
+
"applicationType" | "config" | "isSingleton"
|
|
12
13
|
>;
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -21,13 +22,37 @@ declare const DefineAppInputSchema: z.ZodMiniObject<
|
|
|
21
22
|
{
|
|
22
23
|
applicationType: z.ZodMiniOptional<
|
|
23
24
|
z.ZodMiniEnum<{
|
|
25
|
+
"media-library": "media-library";
|
|
24
26
|
coreApp: "coreApp";
|
|
25
27
|
studio: "studio";
|
|
26
28
|
canvas: "canvas";
|
|
27
29
|
dashboard: "dashboard";
|
|
28
|
-
"media-library": "media-library";
|
|
29
30
|
}>
|
|
30
31
|
>;
|
|
32
|
+
config: z.ZodMiniOptional<
|
|
33
|
+
z.ZodMiniDiscriminatedUnion<
|
|
34
|
+
[
|
|
35
|
+
z.ZodMiniObject<
|
|
36
|
+
{
|
|
37
|
+
appType: z.ZodMiniLiteral<"media-library">;
|
|
38
|
+
fields: z.ZodMiniArray<
|
|
39
|
+
z.ZodMiniObject<
|
|
40
|
+
{
|
|
41
|
+
public: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
42
|
+
title: z.ZodMiniString<string>;
|
|
43
|
+
name: z.ZodMiniString<string>;
|
|
44
|
+
src: z.ZodMiniString<string>;
|
|
45
|
+
},
|
|
46
|
+
z.core.$strip
|
|
47
|
+
>
|
|
48
|
+
>;
|
|
49
|
+
},
|
|
50
|
+
z.core.$strip
|
|
51
|
+
>,
|
|
52
|
+
],
|
|
53
|
+
"appType"
|
|
54
|
+
>
|
|
55
|
+
>;
|
|
31
56
|
entry: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
32
57
|
group: z.ZodMiniOptional<
|
|
33
58
|
z.ZodMiniEnum<{
|
|
@@ -37,6 +62,7 @@ declare const DefineAppInputSchema: z.ZodMiniObject<
|
|
|
37
62
|
}>
|
|
38
63
|
>;
|
|
39
64
|
icon: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
65
|
+
isSingleton: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
40
66
|
name: z.ZodMiniString<string>;
|
|
41
67
|
organizationId: z.ZodMiniString<string>;
|
|
42
68
|
priority: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
@@ -46,6 +72,7 @@ declare const DefineAppInputSchema: z.ZodMiniObject<
|
|
|
46
72
|
[
|
|
47
73
|
z.ZodMiniObject<
|
|
48
74
|
{
|
|
75
|
+
title: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
49
76
|
name: z.ZodMiniString<string>;
|
|
50
77
|
src: z.ZodMiniString<string>;
|
|
51
78
|
type: z.ZodMiniLiteral<"worker">;
|
|
@@ -57,6 +84,7 @@ declare const DefineAppInputSchema: z.ZodMiniObject<
|
|
|
57
84
|
>
|
|
58
85
|
>
|
|
59
86
|
>;
|
|
87
|
+
slug: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
60
88
|
title: z.ZodMiniString<string>;
|
|
61
89
|
views: z.ZodMiniOptional<
|
|
62
90
|
z.ZodMiniArray<
|
|
@@ -64,6 +92,7 @@ declare const DefineAppInputSchema: z.ZodMiniObject<
|
|
|
64
92
|
[
|
|
65
93
|
z.ZodMiniObject<
|
|
66
94
|
{
|
|
95
|
+
title: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
67
96
|
name: z.ZodMiniString<string>;
|
|
68
97
|
src: z.ZodMiniString<string>;
|
|
69
98
|
type: z.ZodMiniLiteral<"panel">;
|
|
@@ -116,6 +145,16 @@ export declare interface DefinedView<
|
|
|
116
145
|
readonly version: typeof VIEW_CONTRACT_VERSION;
|
|
117
146
|
}
|
|
118
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Sanity-owned singleton, so authors don't name or title the app — only `organizationId` is required.
|
|
150
|
+
* @public
|
|
151
|
+
*/
|
|
152
|
+
export declare interface DefineMediaLibraryInput {
|
|
153
|
+
/** Organization that owns the media library — the CLI runs and deploys against it. */
|
|
154
|
+
organizationId: string;
|
|
155
|
+
fields?: MediaLibraryField[];
|
|
156
|
+
}
|
|
157
|
+
|
|
119
158
|
/**
|
|
120
159
|
* Dock group identifier. The API does not block a user app from declaring a
|
|
121
160
|
* reserved group (e.g. `dock.system`); priority conventions keep Sanity-owned
|
|
@@ -131,11 +170,28 @@ declare const DockGroupSchema: z.ZodMiniEnum<{
|
|
|
131
170
|
"dock.user": "dock.user";
|
|
132
171
|
}>;
|
|
133
172
|
|
|
173
|
+
/** @public */
|
|
174
|
+
export declare type InterfaceType = keyof typeof VIEW_COMPONENTS;
|
|
175
|
+
|
|
134
176
|
/**
|
|
135
|
-
*
|
|
177
|
+
* Whether `app` is a branded `unstable_defineApp(...)` result — the sole
|
|
178
|
+
* workbench opt-in.
|
|
136
179
|
* @public
|
|
137
180
|
*/
|
|
138
|
-
export declare
|
|
181
|
+
export declare function isWorkbenchApp(app: unknown): app is WorkbenchApp;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* One custom field a media library exposes. `src` default-exports a `defineField(...)` schema type.
|
|
185
|
+
* @public
|
|
186
|
+
*/
|
|
187
|
+
export declare interface MediaLibraryField {
|
|
188
|
+
/** Unique within the media library. */
|
|
189
|
+
name: string;
|
|
190
|
+
src: string;
|
|
191
|
+
title: string;
|
|
192
|
+
/** Readable outside the owning organization. */
|
|
193
|
+
public?: boolean;
|
|
194
|
+
}
|
|
139
195
|
|
|
140
196
|
/**
|
|
141
197
|
* A panel's view-component slot — the module-federation expose for one island.
|
|
@@ -166,12 +222,7 @@ export declare type PanelViewProps = ViewComponentBaseProps<{
|
|
|
166
222
|
name: string;
|
|
167
223
|
}>;
|
|
168
224
|
|
|
169
|
-
/**
|
|
170
|
-
* Contract version stamped on every defined service. Lets the workbench host
|
|
171
|
-
* and the generated worker artifact evolve the service contract without
|
|
172
|
-
* breaking already-deployed services; bumped only on a breaking change.
|
|
173
|
-
* @internal
|
|
174
|
-
*/
|
|
225
|
+
/** @internal */
|
|
175
226
|
declare const SERVICE_CONTRACT_VERSION = 1;
|
|
176
227
|
|
|
177
228
|
/**
|
|
@@ -206,12 +257,7 @@ export declare interface ServiceInfo {
|
|
|
206
257
|
readonly type: string;
|
|
207
258
|
}
|
|
208
259
|
|
|
209
|
-
/**
|
|
210
|
-
* Every supported service type — the first argument to `unstable_defineService`.
|
|
211
|
-
* Add a service type by adding its declaration schema below and registering it
|
|
212
|
-
* here.
|
|
213
|
-
* @public
|
|
214
|
-
*/
|
|
260
|
+
/** @public */
|
|
215
261
|
export declare type ServiceType = "worker";
|
|
216
262
|
|
|
217
263
|
/**
|
|
@@ -225,6 +271,14 @@ export declare function unstable_defineApp(
|
|
|
225
271
|
input: DefineAppInput,
|
|
226
272
|
): DefineAppResult;
|
|
227
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Declare the Sanity Media Library as a workbench app — a singleton whose `fields` become its config.
|
|
276
|
+
* @public
|
|
277
|
+
*/
|
|
278
|
+
export declare function unstable_defineMediaLibrary(
|
|
279
|
+
input: DefineMediaLibraryInput,
|
|
280
|
+
): DefineAppResult;
|
|
281
|
+
|
|
228
282
|
/**
|
|
229
283
|
* Define a Sanity Workbench background service. The first argument narrows the
|
|
230
284
|
* callback shape — `"worker"` runs the callback inside a Web Worker, where it
|
|
@@ -256,20 +310,15 @@ export declare function unstable_defineView<TType extends InterfaceType>(
|
|
|
256
310
|
): DefinedView<TType>;
|
|
257
311
|
|
|
258
312
|
/**
|
|
259
|
-
* Component slots each interface type exposes, in render order
|
|
260
|
-
*
|
|
261
|
-
* view into one render artifact per component). Add a type by registering it here.
|
|
313
|
+
* Component slots each interface type exposes, in render order. Source of truth
|
|
314
|
+
* for {@link InterfaceType} and the build; add a type by registering it here.
|
|
262
315
|
* @internal
|
|
263
316
|
*/
|
|
264
317
|
declare const VIEW_COMPONENTS: {
|
|
265
318
|
readonly panel: readonly ["title", "panel"];
|
|
266
319
|
};
|
|
267
320
|
|
|
268
|
-
/**
|
|
269
|
-
* Contract version stamped on every defined view — lets the host and the
|
|
270
|
-
* generated artifact evolve the contract without breaking deployed views.
|
|
271
|
-
* @internal
|
|
272
|
-
*/
|
|
321
|
+
/** @internal */
|
|
273
322
|
declare const VIEW_CONTRACT_VERSION = 1;
|
|
274
323
|
|
|
275
324
|
/**
|
|
@@ -279,11 +328,7 @@ declare const VIEW_CONTRACT_VERSION = 1;
|
|
|
279
328
|
*/
|
|
280
329
|
declare type ViewComponent<TProps> = (props: TProps) => unknown;
|
|
281
330
|
|
|
282
|
-
/**
|
|
283
|
-
* Props every view component receives, whatever its type. Per-type props
|
|
284
|
-
* compose from this, so a prop added here reaches every view.
|
|
285
|
-
* @public
|
|
286
|
-
*/
|
|
331
|
+
/** @public */
|
|
287
332
|
declare interface ViewComponentBaseProps<TView> {
|
|
288
333
|
view: TView;
|
|
289
334
|
}
|
|
@@ -304,4 +349,13 @@ export declare interface ViewComponentsByType {
|
|
|
304
349
|
*/
|
|
305
350
|
declare const WORKBENCH_APP: unique symbol;
|
|
306
351
|
|
|
352
|
+
/**
|
|
353
|
+
* A branded app as the CLI reads it — the full schema shape, including the
|
|
354
|
+
* internal fields `DefineAppInput` omits. Schema-derived so the narrowing
|
|
355
|
+
* can't drift from what the schema validates.
|
|
356
|
+
* @public
|
|
357
|
+
*/
|
|
358
|
+
export declare type WorkbenchApp = DefineAppResult &
|
|
359
|
+
z.output<typeof DefineAppInputSchema>;
|
|
360
|
+
|
|
307
361
|
export {};
|
package/dist/_exports/index.js
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
// authors call from `sanity.cli.ts` (re-exported by `sanity/cli` and the
|
|
3
|
-
// `sanity` runtime entry). Calling `unstable_defineApp` is the *sole* workbench
|
|
4
|
-
// opt-in: it stamps the global brand `Symbol.for('sanity.workbench.defineApp')`,
|
|
5
|
-
// which the CLI discriminates on (see `isWorkbenchApp` in `@sanity/cli-core`).
|
|
6
|
-
//
|
|
7
|
-
// This module graph must stay browser-safe: zod-only, no `node:*`, no vite, no
|
|
8
|
-
// `@sanity/cli-core`. View/service `src` files bundle to the browser, so anything
|
|
9
|
-
// reachable from here ships in the frontend bundle. The Node-only build glue
|
|
10
|
-
// lives behind the separate `./vite` entry and never leaks in.
|
|
11
|
-
export { unstable_defineApp } from '../defineApp.js';
|
|
1
|
+
export { isWorkbenchApp, unstable_defineApp, unstable_defineMediaLibrary } from '../defineApp.js';
|
|
12
2
|
export { unstable_defineService } from '../defineService.js';
|
|
13
3
|
export { unstable_defineView } from '../defineView.js';
|
|
14
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/_exports/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/_exports/index.ts"],"sourcesContent":["export type {InterfaceType, ServiceType} from '../contract.js'\nexport {isWorkbenchApp, unstable_defineApp, unstable_defineMediaLibrary} from '../defineApp.js'\nexport type {\n DefineAppInput,\n DefineAppResult,\n DefineMediaLibraryInput,\n DockGroup,\n MediaLibraryField,\n WorkbenchApp,\n} from '../defineApp.js'\nexport {unstable_defineService} from '../defineService.js'\nexport type {\n DefinedService,\n ServiceCallback,\n ServiceContext,\n ServiceInfo,\n} from '../defineService.js'\nexport {unstable_defineView} from '../defineView.js'\nexport type {\n DefinedView,\n PanelComponent,\n PanelViewComponents,\n PanelViewProps,\n ViewComponentsByType,\n} from '../defineView.js'\n"],"names":["isWorkbenchApp","unstable_defineApp","unstable_defineMediaLibrary","unstable_defineService","unstable_defineView"],"mappings":"AACA,SAAQA,cAAc,EAAEC,kBAAkB,EAAEC,2BAA2B,QAAO,kBAAiB;AAS/F,SAAQC,sBAAsB,QAAO,sBAAqB;AAO1D,SAAQC,mBAAmB,QAAO,mBAAkB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { configArtifacts } from './configs/artifact.js';
|
|
1
2
|
import { serviceArtifacts } from './services/artifact.js';
|
|
2
3
|
import { viewArtifacts } from './views/artifact.js';
|
|
3
4
|
/**
|
|
@@ -15,14 +16,14 @@ import { viewArtifacts } from './views/artifact.js';
|
|
|
15
16
|
return exposes;
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
18
|
-
* Expand
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
*/ export function workbenchArtifacts(options) {
|
|
19
|
+
* Expand what the app exposes into the flat artifact set the federation build
|
|
20
|
+
* writes — the single place that composes the per-type expanders, so the expose
|
|
21
|
+
* mapping and the file writing read from one expansion.
|
|
22
|
+
*/ export function workbenchArtifacts(exposes) {
|
|
23
23
|
return [
|
|
24
|
-
...viewArtifacts(
|
|
25
|
-
...serviceArtifacts(
|
|
24
|
+
...viewArtifacts(exposes.views ?? []),
|
|
25
|
+
...serviceArtifacts(exposes.services ?? []),
|
|
26
|
+
...configArtifacts(exposes.config)
|
|
26
27
|
];
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/build/artifact.ts"],"sourcesContent":["import {type
|
|
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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { INSTALLATION_CONFIG_TYPE, MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION } from '../../../contract.js';
|
|
2
|
+
const CONFIGS_DIR_NAME = 'configs';
|
|
3
|
+
/** Expand the config into one federation module aggregating all fields, so the host imports one live config value. */ export function configArtifacts(config) {
|
|
4
|
+
if (!config) return [];
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
expose: `./${CONFIGS_DIR_NAME}/${INSTALLATION_CONFIG_TYPE}`,
|
|
8
|
+
path: `${CONFIGS_DIR_NAME}/${INSTALLATION_CONFIG_TYPE}.js`,
|
|
9
|
+
source: ({ resolveImport })=>mediaLibraryConfigSource({
|
|
10
|
+
config,
|
|
11
|
+
resolveImport
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Emits `export const config`: each field's serializable `{name, title, public}`
|
|
18
|
+
* plus its live `defineField` value, the one thing the wire can't carry.
|
|
19
|
+
* `appType` stays off the module — the host assigns it from the wire record.
|
|
20
|
+
*/ function mediaLibraryConfigSource(input) {
|
|
21
|
+
const { config, resolveImport } = input;
|
|
22
|
+
const imports = config.fields.map((field, index)=>`import field_${index} from ${JSON.stringify(resolveImport(field.src))}`).join('\n');
|
|
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');
|
|
24
|
+
return `\
|
|
25
|
+
// This file is auto-generated on 'sanity build' / 'sanity dev'
|
|
26
|
+
// Modifications to this file are automatically discarded
|
|
27
|
+
${imports}
|
|
28
|
+
|
|
29
|
+
export const type = ${JSON.stringify(INSTALLATION_CONFIG_TYPE)}
|
|
30
|
+
export const version = ${MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION}
|
|
31
|
+
export const config = {
|
|
32
|
+
fields: [
|
|
33
|
+
${entries}
|
|
34
|
+
],
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (import.meta.hot) {
|
|
38
|
+
// A config is data, not a rendered island with a live root to remount —
|
|
39
|
+
// self-accept so a field edit swaps the module in place; the host re-reads it.
|
|
40
|
+
import.meta.hot.accept()
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -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
|
|
11
|
+
const { exposes, name: defaultName, pkgJson, workDir = process.cwd() } = options;
|
|
12
12
|
let name = defaultName;
|
|
13
13
|
if (!name) {
|
|
14
14
|
name = pkgJson?.name;
|
|
@@ -25,29 +25,21 @@ import { sanityFederationRuntime } from './plugins/plugin-sanity-federation-runt
|
|
|
25
25
|
return resolvedPath;
|
|
26
26
|
}
|
|
27
27
|
const entryPath = resolveEntryPath(generatedEntry);
|
|
28
|
-
const resolvedExposes = {};
|
|
29
|
-
for (const [key, exposePath] of Object.entries(defaultExposes)){
|
|
30
|
-
resolvedExposes[key] = resolveEntryPath(exposePath) ?? exposePath;
|
|
31
|
-
}
|
|
32
28
|
// Each view component (`./views/<view>/<component>`) and each service loader
|
|
33
29
|
// (`./services/<name>`) is exposed straight to the host, pointing at the file
|
|
34
30
|
// the extension-artifacts plugin generates under RUNTIME_DIR. A service's
|
|
35
31
|
// worker bundle carries no expose — the host reaches it through its loader.
|
|
36
|
-
const artifacts = workbenchArtifacts({
|
|
37
|
-
|
|
38
|
-
views
|
|
39
|
-
});
|
|
40
|
-
const interfaceExposes = artifactExposes(artifacts, (artifactPath)=>resolveEntryPath(`./${RUNTIME_DIR}/${artifactPath}`));
|
|
32
|
+
const artifacts = workbenchArtifacts(exposes ?? {});
|
|
33
|
+
const artifactModuleExposes = artifactExposes(artifacts, (artifactPath)=>resolveEntryPath(`./${RUNTIME_DIR}/${artifactPath}`));
|
|
41
34
|
// A dock-only app (`isApp` with no `appEntry`) has no navigable full-page
|
|
42
35
|
// view, so it exposes no `./App` — only its views. Studios and apps with an
|
|
43
36
|
// entry expose `./App` (the generated render entry).
|
|
44
37
|
const exposesApp = !options.isApp || options.appEntry !== undefined;
|
|
45
|
-
const
|
|
38
|
+
const federationExposes = {
|
|
46
39
|
...exposesApp ? {
|
|
47
40
|
'./App': entryPath
|
|
48
41
|
} : {},
|
|
49
|
-
...
|
|
50
|
-
...interfaceExposes
|
|
42
|
+
...artifactModuleExposes
|
|
51
43
|
};
|
|
52
44
|
const runtimeOptions = options.isApp ? {
|
|
53
45
|
appEntry: options.appEntry,
|
|
@@ -65,7 +57,7 @@ import { sanityFederationRuntime } from './plugins/plugin-sanity-federation-runt
|
|
|
65
57
|
artifacts
|
|
66
58
|
}),
|
|
67
59
|
sanityModuleFederation({
|
|
68
|
-
exposes,
|
|
60
|
+
exposes: federationExposes,
|
|
69
61
|
name
|
|
70
62
|
})
|
|
71
63
|
];
|
|
@@ -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
|
|
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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bake the app's bus identity into its bundle: `@sanity/runtime` reads
|
|
3
|
+
* `__SANITY_APP_ID__` where it connects. `define` covers everything the
|
|
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
|
|
6
|
+
* define transform.
|
|
7
|
+
*/ export function sanityAppId(appId) {
|
|
8
|
+
const define = {
|
|
9
|
+
__SANITY_APP_ID__: JSON.stringify(appId)
|
|
10
|
+
};
|
|
11
|
+
return {
|
|
12
|
+
config: ()=>({
|
|
13
|
+
define,
|
|
14
|
+
optimizeDeps: {
|
|
15
|
+
esbuildOptions: {
|
|
16
|
+
define
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}),
|
|
20
|
+
name: 'sanity/workbench/app-id'
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=plugin-sanity-app-id.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { readPackageJson } from '@sanity/cli-core';
|
|
9
9
|
import { federation } from './plugin.js';
|
|
10
|
+
import { sanityAppId } from './plugins/plugin-sanity-app-id.js';
|
|
10
11
|
/**
|
|
11
12
|
* A workbench studio renders from its `sanity.config.*`, so the build needs one.
|
|
12
13
|
* An explicit `applicationType: 'studio'` wins over detection, so a studio can
|
|
@@ -19,9 +20,9 @@ import { federation } from './plugin.js';
|
|
|
19
20
|
return relativeConfigLocation;
|
|
20
21
|
}
|
|
21
22
|
/** Build the Vite plugins for a workbench app's module-federation remote. */ export async function workbenchVitePlugins(options) {
|
|
22
|
-
const { cwd, entries,
|
|
23
|
+
const { appId, cwd, entries, exposes, isApp } = options;
|
|
23
24
|
const pkgJson = await readPackageJson(path.join(cwd, 'package.json'));
|
|
24
|
-
|
|
25
|
+
const federationPlugin = federation({
|
|
25
26
|
...isApp ? {
|
|
26
27
|
// `null` relativeEntry (a branded app with no `entry`) → omit `appEntry`,
|
|
27
28
|
// so the remote exposes no `./App`, only its views.
|
|
@@ -33,11 +34,14 @@ import { federation } from './plugin.js';
|
|
|
33
34
|
isApp: false,
|
|
34
35
|
studioConfigPath: requireStudioConfigPath(entries.relativeConfigLocation)
|
|
35
36
|
},
|
|
37
|
+
exposes,
|
|
36
38
|
pkgJson,
|
|
37
|
-
services,
|
|
38
|
-
views,
|
|
39
39
|
workDir: cwd
|
|
40
40
|
});
|
|
41
|
+
return appId === undefined ? federationPlugin : [
|
|
42
|
+
federationPlugin,
|
|
43
|
+
sanityAppId(appId)
|
|
44
|
+
];
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
//# sourceMappingURL=workbench-vite-plugins.js.map
|
|
@@ -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
|
|
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 `unstable_defineApp` \" +\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,8EACA;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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/apiVersion.ts"],"sourcesContent":["// The app endpoints (applications + installations) live behind the\n// experimental `vX` version; a dated version returns 501.\nexport const APP_WORKBENCH_API_VERSION = 'vX'\n"],"names":["APP_WORKBENCH_API_VERSION"],"mappings":"AAAA,mEAAmE;AACnE,0DAA0D;AAC1D,OAAO,MAAMA,4BAA4B,KAAI"}
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
function summarizeExposeGroup(heading, items) {
|
|
28
|
+
const label = (item)=>item.title === item.name ? item.name : `${item.title} (${item.name})`;
|
|
29
|
+
return `${heading}:\n${items.map((item)=>` ${label(item)}: ${item.src}`).join('\n')}`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The deploy summary of an app's exposes: the structured records (for `--json`)
|
|
33
|
+
* and one report line per non-empty group (for the human report).
|
|
34
|
+
* @internal
|
|
35
|
+
*/ export function summarizeExposes({ services, views }) {
|
|
36
|
+
const toExpose = (decl)=>({
|
|
37
|
+
name: decl.name,
|
|
38
|
+
src: decl.src,
|
|
39
|
+
title: decl.title ?? decl.name,
|
|
40
|
+
type: decl.type
|
|
41
|
+
});
|
|
42
|
+
const viewExposes = (views ?? []).map((view)=>toExpose(view));
|
|
43
|
+
const serviceExposes = (services ?? []).map((service)=>toExpose(service));
|
|
44
|
+
const lines = [];
|
|
45
|
+
if (viewExposes.length > 0) lines.push(summarizeExposeGroup('Views', viewExposes));
|
|
46
|
+
if (serviceExposes.length > 0) lines.push(summarizeExposeGroup('Services', serviceExposes));
|
|
47
|
+
return {
|
|
48
|
+
exposes: [
|
|
49
|
+
...viewExposes,
|
|
50
|
+
...serviceExposes
|
|
51
|
+
],
|
|
52
|
+
lines
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=buildExposes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/buildExposes.ts"],"sourcesContent":["import {type WorkbenchExposes} from '../../resolveWorkbenchApp.js'\n\n/**\n * An interface as Brett stores it: the declared `type` (validated server-side,\n * not here) and the remote-relative `moduleId` the workbench loads it by — the\n * host prepends the app's own id.\n * @internal\n */\nexport interface BrettInterface {\n moduleId: string\n name: string\n title: string\n type: string\n version: string\n}\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\nfunction summarizeExposeGroup(heading: string, items: readonly DeployedExpose[]): string {\n const label = (item: DeployedExpose) =>\n item.title === item.name ? item.name : `${item.title} (${item.name})`\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","summarizeExposeGroup","heading","items","label","item","map","src","join","summarizeExposes","toExpose","viewExposes","serviceExposes","lines","length"],"mappings":"AAwBA;;;;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,SAASM,qBAAqBC,OAAe,EAAEC,KAAgC;IAC7E,MAAMC,QAAQ,CAACC,OACbA,KAAKZ,KAAK,KAAKY,KAAKb,IAAI,GAAGa,KAAKb,IAAI,GAAG,GAAGa,KAAKZ,KAAK,CAAC,EAAE,EAAEY,KAAKb,IAAI,CAAC,CAAC,CAAC;IACvE,OAAO,GAAGU,QAAQ,GAAG,EAAEC,MAAMG,GAAG,CAAC,CAACD,OAAS,CAAC,EAAE,EAAED,MAAMC,MAAM,EAAE,EAAEA,KAAKE,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,CAACK,qBAAqB,SAASU;IACrE,IAAIC,eAAeE,MAAM,GAAG,GAAGD,MAAMjB,IAAI,CAACK,qBAAqB,YAAYW;IAC3E,OAAO;QAAC7B,SAAS;eAAI4B;eAAgBC;SAAe;QAAEC;IAAK;AAC7D"}
|