@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.
- package/dist/_exports/build.d.ts +22 -17
- package/dist/_exports/deploy.d.ts +169 -23
- package/dist/_exports/deploy.js +4 -1
- package/dist/_exports/deploy.js.map +1 -1
- package/dist/_exports/dev.d.ts +9 -5
- package/dist/_exports/index.d.ts +19 -15
- package/dist/_exports/undeploy.d.ts +248 -0
- package/dist/_exports/undeploy.js +3 -0
- package/dist/_exports/undeploy.js.map +1 -0
- package/dist/actions/build/artifact.js +2 -2
- package/dist/actions/build/artifact.js.map +1 -1
- package/dist/actions/build/configs/artifact.js +5 -5
- package/dist/actions/build/configs/artifact.js.map +1 -1
- package/dist/actions/build/vite/plugin.js +5 -0
- package/dist/actions/build/vite/plugin.js.map +1 -1
- package/dist/actions/build/vite/plugins/plugin-sanity-app-id.js +5 -3
- package/dist/actions/build/vite/plugins/plugin-sanity-app-id.js.map +1 -1
- package/dist/actions/build/vite/plugins/plugin-sanity-environment.js +26 -2
- package/dist/actions/build/vite/plugins/plugin-sanity-environment.js.map +1 -1
- package/dist/actions/deploy/buildExposes.js +59 -0
- package/dist/actions/deploy/buildExposes.js.map +1 -0
- package/dist/actions/deploy/checkBuiltOutput.js +4 -3
- package/dist/actions/deploy/checkBuiltOutput.js.map +1 -1
- package/dist/actions/deploy/deployConfig.js +63 -0
- package/dist/actions/deploy/deployConfig.js.map +1 -0
- package/dist/actions/deploy/deployWorkbenchApp.js +108 -0
- package/dist/actions/deploy/deployWorkbenchApp.js.map +1 -0
- package/dist/actions/deploy/getWorkbench.js +4 -4
- package/dist/actions/deploy/getWorkbench.js.map +1 -1
- package/dist/actions/dev/deriveInterfaces.js +43 -32
- package/dist/actions/dev/deriveInterfaces.js.map +1 -1
- package/dist/actions/dev/exposesSetId.js +8 -8
- package/dist/actions/dev/exposesSetId.js.map +1 -1
- package/dist/actions/dev/registry.js +22 -12
- package/dist/actions/dev/registry.js.map +1 -1
- package/dist/actions/dev/startDevManifestWatcher.js +2 -2
- package/dist/actions/dev/startDevManifestWatcher.js.map +1 -1
- package/dist/actions/dev/startDevServerRegistration.js +7 -7
- package/dist/actions/dev/startDevServerRegistration.js.map +1 -1
- package/dist/actions/dev/startWorkbenchDevServer.js +9 -6
- 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/actions/undeploy/workbenchUndeployAdapter.js +150 -0
- package/dist/actions/undeploy/workbenchUndeployAdapter.js.map +1 -0
- package/dist/contract.js +16 -8
- package/dist/contract.js.map +1 -1
- package/dist/defineApp.js +25 -20
- package/dist/defineApp.js.map +1 -1
- package/dist/defineView.js.map +1 -1
- package/dist/resolveWorkbenchApp.js +4 -3
- package/dist/resolveWorkbenchApp.js.map +1 -1
- package/dist/services/apiVersion.js +5 -0
- package/dist/services/apiVersion.js.map +1 -0
- package/dist/services/applications.js +100 -0
- package/dist/services/applications.js.map +1 -0
- package/dist/services/installations.js +63 -0
- package/dist/services/installations.js.map +1 -0
- package/package.json +7 -3
- package/dist/actions/deploy/deployInstallationConfig.js +0 -91
- 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 @@
|
|
|
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 {
|
|
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
|
-
...
|
|
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 {
|
|
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,
|
|
1
|
+
import { INSTALLATION_CONFIG_TYPE, MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION } from '../../../contract.js';
|
|
2
2
|
const CONFIGS_DIR_NAME = 'configs';
|
|
3
|
-
/** Expand the
|
|
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 })=>
|
|
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
|
|
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 = ${
|
|
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 {
|
|
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;
|
|
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
|
-
*
|
|
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
|
-
|
|
16
|
-
|
|
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 *
|
|
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
|
-
|
|
17
|
-
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
|
|
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
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* marker that `sanity build` produced a
|
|
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 *
|
|
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"}
|